<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="c++-总结, 戴某的博客">
    <meta name="description" content="戴某的笔记">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>c++-总结 | 戴某的博客</title>
    <link rel="icon" type="image/png" href="/dai_modest/favicon.png">

    <link rel="stylesheet" type="text/css" href="/dai_modest/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/dai_modest/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/dai_modest/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/dai_modest/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/dai_modest/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/dai_modest/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/dai_modest/css/my.css">

    <script src="/dai_modest/libs/jquery/jquery.min.js"></script>

<meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/dai_modest/atom.xml" title="戴某的博客" type="application/atom+xml">
<link rel="stylesheet" href="/dai_modest/css/prism-tomorrow.css" type="text/css"></head>



   <style>
    body{
       background-image: url(https://cdn.jsdelivr.net/gh/Tokisaki-Galaxy/res/site/medias/background.jpg);
       background-repeat:no-repeat;
       background-size:cover;
       background-attachment:fixed;
    }
</style>



<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/dai_modest/" class="waves-effect waves-light">
                    
                    <img src="/dai_modest/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">戴某的博客</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/dai_modest/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/dai_modest/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/dai_modest/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/dai_modest/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/dai_modest/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/dai_modest/contact" class="waves-effect waves-light">
      
      <i class="fas fa-comments" style="zoom: 0.6;"></i>
      
      <span>留言板</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/dai_modest/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/dai_modest/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">戴某的博客</div>
        <div class="logo-desc">
            
            戴某的笔记
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/dai_modest/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/dai_modest/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/dai_modest/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/dai_modest/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/dai_modest/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/dai_modest/contact" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-comments"></i>
			
			留言板
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/dai_modest/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
        <li><div class="divider"></div></li>
        <li>
            <a href="https://github.com/blinkfox/hexo-theme-matery" class="waves-effect waves-light" target="_blank">
                <i class="fab fa-github-square fa-fw"></i>Fork Me
            </a>
        </li>
        
    </ul>
</div>


        </div>

        
            <style>
    .nav-transparent .github-corner {
        display: none !important;
    }

    .github-corner {
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        border: 0;
        transform: scale(1.1);
    }

    .github-corner svg {
        color: #0f9d58;
        fill: #fff;
        height: 64px;
        width: 64px;
    }

    .github-corner:hover .octo-arm {
        animation: a 0.56s ease-in-out;
    }

    .github-corner .octo-arm {
        animation: none;
    }

    @keyframes a {
        0%,
        to {
            transform: rotate(0);
        }
        20%,
        60% {
            transform: rotate(-25deg);
        }
        40%,
        80% {
            transform: rotate(10deg);
        }
    }
</style>

<a href="https://github.com/blinkfox/hexo-theme-matery" class="github-corner tooltipped hide-on-med-and-down" target="_blank"
   data-tooltip="Fork Me" data-position="left" data-delay="50">
    <svg viewBox="0 0 250 250" aria-hidden="true">
        <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
        <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
              fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
        <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
              fill="currentColor" class="octo-body"></path>
    </svg>
</a>
        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/dai_modest/medias/featureimages/14.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">c++-总结</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/dai_modest/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/dai_modest/tags/c/">
                                <span class="chip bg-color">c++</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/dai_modest/categories/c/" class="post-category">
                                c++
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2021-09-07
                </div>
                

                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-check fa-fw"></i>更新日期:&nbsp;&nbsp;
                    2021-09-08
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    580
                </div>
                

                

                
            </div>
        </div>
        <hr class="clearfix">

        
        <!-- 是否加载使用自带的 prismjs. -->
        <link rel="stylesheet" href="/dai_modest/libs/prism/prism.css">
        

        
        <!-- 代码块折行 -->
        <style type="text/css">
            code[class*="language-"], pre[class*="language-"] { white-space: pre-wrap !important; }
        </style>
        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="C-核心编程"><a href="#C-核心编程" class="headerlink" title="C++核心编程"></a>C++核心编程</h1><p>本阶段主要针对C++==面向对象==编程技术做详细讲解，探讨C++中的核心和精髓。</p>
<h2 id="1-内存分区模型"><a href="#1-内存分区模型" class="headerlink" title="1 内存分区模型"></a>1 内存分区模型</h2><p>C++程序在执行时，将内存大方向划分为<strong>4个区域</strong></p>
<ul>
<li>代码区：存放函数体的二进制代码，由操作系统进行管理的</li>
<li>全局区：存放全局变量和静态变量以及常量</li>
<li>栈区：由编译器自动分配释放, 存放函数的参数值,局部变量等</li>
<li>堆区：由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收</li>
</ul>
<p><strong>内存四区意义：</strong></p>
<p>不同区域存放的数据，赋予不同的生命周期, 给我们更大的灵活编程</p>
<h3 id="1-1-程序运行前"><a href="#1-1-程序运行前" class="headerlink" title="1.1 程序运行前"></a>1.1 程序运行前</h3><p>​    在程序编译后，生成了exe可执行程序，<strong>未执行该程序前</strong>分为两个区域</p>
<p>​    <strong>代码区：</strong></p>
<p>​        存放 CPU 执行的机器指令</p>
<p>​        代码区是<strong>共享</strong>的，共享的目的是对于频繁被执行的程序，只需要在内存中有一份代码即可</p>
<p>​        代码区是<strong>只读</strong>的，使其只读的原因是防止程序意外地修改了它的指令</p>
<p>​    <strong>全局区：</strong></p>
<p>​        全局变量和静态变量存放在此.</p>
<p>​        全局区还包含了常量区, 字符串常量和其他常量也存放在此.</p>
<p>​        ==该区域的数据在程序结束后由操作系统释放==.</p>
<p><strong>示例：</strong></p>
<pre class=" language-c++"><code class="language-c++">//全局变量
int g_a = 10;
int g_b = 10;

//全局常量
const int c_g_a = 10;
const int c_g_b = 10;

int main() &#123;

    //局部变量
    int a = 10;
    int b = 10;

    //打印地址
    cout << "局部变量a地址为： " << (int)&a << endl;
    cout << "局部变量b地址为： " << (int)&b << endl;

    cout << "全局变量g_a地址为： " <<  (int)&g_a << endl;
    cout << "全局变量g_b地址为： " <<  (int)&g_b << endl;

    //静态变量
    static int s_a = 10;
    static int s_b = 10;

    cout << "静态变量s_a地址为： " << (int)&s_a << endl;
    cout << "静态变量s_b地址为： " << (int)&s_b << endl;

    cout << "字符串常量地址为： " << (int)&"hello world" << endl;
    cout << "字符串常量地址为： " << (int)&"hello world1" << endl;

    cout << "全局常量c_g_a地址为： " << (int)&c_g_a << endl;
    cout << "全局常量c_g_b地址为： " << (int)&c_g_b << endl;

    const int c_l_a = 10;
    const int c_l_b = 10;
    cout << "局部常量c_l_a地址为： " << (int)&c_l_a << endl;
    cout << "局部常量c_l_b地址为： " << (int)&c_l_b << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<p>打印结果：</p>




<p>总结：</p>
<ul>
<li>C++中在程序运行前分为全局区和代码区</li>
<li>代码区特点是共享和只读</li>
<li>全局区中存放全局变量、静态变量、常量</li>
<li>常量区中存放 const修饰的全局常量  和 字符串常量</li>
</ul>
<h3 id="1-2-程序运行后"><a href="#1-2-程序运行后" class="headerlink" title="1.2 程序运行后"></a>1.2 程序运行后</h3><p>​    <strong>栈区：</strong></p>
<p>​        由编译器自动分配释放, 存放函数的参数值,局部变量等</p>
<p>​        注意事项：不要返回局部变量的地址，栈区开辟的数据由编译器自动释放</p>
<p><strong>示例：</strong></p>
<pre class=" language-c++"><code class="language-c++">int * func()
&#123;
    int a = 10;
    return &a;
&#125;

int main() &#123;

    int *p = func();

    cout << *p << endl;
    cout << *p << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<p>​    <strong>堆区：</strong></p>
<p>​        由程序员分配释放,若程序员不释放,程序结束时由操作系统回收</p>
<p>​        在C++中主要利用new在堆区开辟内存</p>
<p><strong>示例：</strong></p>
<pre class=" language-c++"><code class="language-c++">int* func()
&#123;
    int* a = new int(10);
    return a;
&#125;

int main() &#123;

    int *p = func();

    cout << *p << endl;
    cout << *p << endl;
    
    system("pause");

    return 0;
&#125;
</code></pre>
<p><strong>总结：</strong></p>
<p>堆区数据由程序员管理开辟和释放</p>
<p>堆区数据利用new关键字进行开辟内存</p>
<h3 id="1-3-new操作符"><a href="#1-3-new操作符" class="headerlink" title="1.3 new操作符"></a>1.3 new操作符</h3><p>​    C++中利用==new==操作符在堆区开辟数据</p>
<p>​    堆区开辟的数据，由程序员手动开辟，手动释放，释放利用操作符 ==delete==</p>
<p>​    语法：<code> new 数据类型</code></p>
<p>​    利用new创建的数据，会返回该数据对应的类型的指针</p>
<p><strong>示例1： 基本语法</strong></p>
<pre class=" language-c++"><code class="language-c++">int* func()
&#123;
    int* a = new int(10);
    return a;
&#125;

int main() &#123;

    int *p = func();

    cout << *p << endl;
    cout << *p << endl;

    //利用delete释放堆区数据
    delete p;

    //cout << *p << endl; //报错，释放的空间不可访问

    system("pause");

    return 0;
&#125;
</code></pre>
<p><strong>示例2：开辟数组</strong></p>
<pre class=" language-c++"><code class="language-c++">//堆区开辟数组
int main() &#123;

    int* arr = new int[10];

    for (int i = 0; i < 10; i++)
    &#123;
        arr[i] = i + 100;
    &#125;

    for (int i = 0; i < 10; i++)
    &#123;
        cout << arr[i] << endl;
    &#125;
    //释放数组 delete 后加 []
    delete[] arr;

    system("pause");

    return 0;
&#125;
</code></pre>
<h2 id="2-引用"><a href="#2-引用" class="headerlink" title="2 引用"></a>2 引用</h2><h3 id="2-1-引用的基本使用"><a href="#2-1-引用的基本使用" class="headerlink" title="2.1 引用的基本使用"></a>2.1 引用的基本使用</h3><p>**作用： **给变量起别名</p>
<p><strong>语法：</strong> <code>数据类型 &amp;别名 = 原名</code></p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">int main() &#123;

    int a = 10;
    int &b = a;

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    b = 100;

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<h3 id="2-2-引用注意事项"><a href="#2-2-引用注意事项" class="headerlink" title="2.2 引用注意事项"></a>2.2 引用注意事项</h3><ul>
<li>引用必须初始化</li>
<li>引用在初始化后，不可以改变</li>
</ul>
<p>示例：</p>
<pre class=" language-C++"><code class="language-C++">int main() &#123;

    int a = 10;
    int b = 20;
    //int &c; //错误，引用必须初始化
    int &c = a; //一旦初始化后，就不可以更改
    c = b; //这是赋值操作，不是更改引用

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<h3 id="2-3-引用做函数参数"><a href="#2-3-引用做函数参数" class="headerlink" title="2.3 引用做函数参数"></a>2.3 引用做函数参数</h3><p><strong>作用：</strong>函数传参时，可以利用引用的技术让形参修饰实参</p>
<p><strong>优点：</strong>可以简化指针修改实参</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//1. 值传递
void mySwap01(int a, int b) &#123;
    int temp = a;
    a = b;
    b = temp;
&#125;

//2. 地址传递
void mySwap02(int* a, int* b) &#123;
    int temp = *a;
    *a = *b;
    *b = temp;
&#125;

//3. 引用传递
void mySwap03(int& a, int& b) &#123;
    int temp = a;
    a = b;
    b = temp;
&#125;

int main() &#123;

    int a = 10;
    int b = 20;

    mySwap01(a, b);
    cout << "a:" << a << " b:" << b << endl;

    mySwap02(&a, &b);
    cout << "a:" << a << " b:" << b << endl;

    mySwap03(a, b);
    cout << "a:" << a << " b:" << b << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结：通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单</p>
</blockquote>
<h3 id="2-4-引用做函数返回值"><a href="#2-4-引用做函数返回值" class="headerlink" title="2.4 引用做函数返回值"></a>2.4 引用做函数返回值</h3><p>作用：引用是可以作为函数的返回值存在的</p>
<p>注意：<strong>不要返回局部变量引用</strong></p>
<p>用法：函数调用作为左值</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//返回局部变量引用
int& test01() &#123;
    int a = 10; //局部变量
    return a;
&#125;

//返回静态变量引用
int& test02() &#123;
    static int a = 20;
    return a;
&#125;

int main() &#123;

    //不能返回局部变量的引用
    int& ref = test01();
    cout << "ref = " << ref << endl;
    cout << "ref = " << ref << endl;

    //如果函数做左值，那么必须返回引用
    int& ref2 = test02();
    cout << "ref2 = " << ref2 << endl;
    cout << "ref2 = " << ref2 << endl;

    test02() = 1000;

    cout << "ref2 = " << ref2 << endl;
    cout << "ref2 = " << ref2 << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<p>​    </p>
<h3 id="2-5-引用的本质"><a href="#2-5-引用的本质" class="headerlink" title="2.5 引用的本质"></a>2.5 引用的本质</h3><p>本质：<strong>引用的本质在c++内部实现是一个指针常量.</strong></p>
<p>讲解示例：</p>
<pre class=" language-C++"><code class="language-C++">//发现是引用，转换为 int* const ref = &a;
void func(int& ref)&#123;
    ref = 100; // ref是引用，转换为*ref = 100
&#125;
int main()&#123;
    int a = 10;
    
    //自动转换为 int* const ref = &a; 指针常量是指针指向不可改，也说明为什么引用不可更改
    int& ref = a; 
    ref = 20; //内部发现ref是引用，自动帮我们转换为: *ref = 20;
    
    cout << "a:" << a << endl;
    cout << "ref:" << ref << endl;
    
    func(a);
    return 0;
&#125;
</code></pre>
<p>结论：C++推荐用引用技术，因为语法方便，引用本质是指针常量，但是所有的指针操作编译器都帮我们做了</p>
<h3 id="2-6-常量引用"><a href="#2-6-常量引用" class="headerlink" title="2.6 常量引用"></a>2.6 常量引用</h3><p><strong>作用：</strong>常量引用主要用来修饰形参，防止误操作</p>
<p>在函数形参列表中，可以加==const修饰形参==，防止形参改变实参</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//引用使用的场景，通常用来修饰形参
void showValue(const int& v) &#123;
    //v += 10;
    cout << v << endl;
&#125;

int main() &#123;

    //int& ref = 10;  引用本身需要一个合法的内存空间，因此这行错误
    //加入const就可以了，编译器优化代码，int temp = 10; const int& ref = temp;
    const int& ref = 10;

    //ref = 100;  //加入const后不可以修改变量
    cout << ref << endl;

    //函数中利用常量引用防止误操作修改实参
    int a = 10;
    showValue(a);

    system("pause");

    return 0;
&#125;
</code></pre>
<h2 id="3-函数提高"><a href="#3-函数提高" class="headerlink" title="3 函数提高"></a>3 函数提高</h2><h3 id="3-1-函数默认参数"><a href="#3-1-函数默认参数" class="headerlink" title="3.1 函数默认参数"></a>3.1 函数默认参数</h3><p>在C++中，函数的形参列表中的形参是可以有默认值的。</p>
<p>语法：<code> 返回值类型  函数名 （参数= 默认值）&#123;&#125;</code></p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">int func(int a, int b = 10, int c = 10) &#123;
    return a + b + c;
&#125;

//1. 如果某个位置参数有默认值，那么从这个位置往后，从左向右，必须都要有默认值
//2. 如果函数声明有默认值，函数实现的时候就不能有默认参数
int func2(int a = 10, int b = 10);
int func2(int a, int b) &#123;
    return a + b;
&#125;

int main() &#123;

    cout << "ret = " << func(20, 20) << endl;
    cout << "ret = " << func(100) << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<h3 id="3-2-函数占位参数"><a href="#3-2-函数占位参数" class="headerlink" title="3.2 函数占位参数"></a>3.2 函数占位参数</h3><p>C++中函数的形参列表里可以有占位参数，用来做占位，调用函数时必须填补该位置</p>
<p><strong>语法：</strong> <code>返回值类型 函数名 (数据类型)&#123;&#125;</code></p>
<p>在现阶段函数的占位参数存在意义不大，但是后面的课程中会用到该技术</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//函数占位参数 ，占位参数也可以有默认参数
void func(int a, int) &#123;
    cout << "this is func" << endl;
&#125;

int main() &#123;

    func(10,10); //占位参数必须填补

    system("pause");

    return 0;
&#125;
</code></pre>
<h3 id="3-3-函数重载"><a href="#3-3-函数重载" class="headerlink" title="3.3 函数重载"></a>3.3 函数重载</h3><h4 id="3-3-1-函数重载概述"><a href="#3-3-1-函数重载概述" class="headerlink" title="3.3.1 函数重载概述"></a>3.3.1 函数重载概述</h4><p><strong>作用：</strong>函数名可以相同，提高复用性</p>
<p><strong>函数重载满足条件：</strong></p>
<ul>
<li>同一个作用域下</li>
<li>函数名称相同</li>
<li>函数参数<strong>类型不同</strong>  或者 <strong>个数不同</strong> 或者 <strong>顺序不同</strong></li>
</ul>
<p><strong>注意:</strong>  函数的返回值不可以作为函数重载的条件</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//函数重载需要函数都在同一个作用域下
void func()
&#123;
    cout << "func 的调用！" << endl;
&#125;
void func(int a)
&#123;
    cout << "func (int a) 的调用！" << endl;
&#125;
void func(double a)
&#123;
    cout << "func (double a)的调用！" << endl;
&#125;
void func(int a ,double b)
&#123;
    cout << "func (int a ,double b) 的调用！" << endl;
&#125;
void func(double a ,int b)
&#123;
    cout << "func (double a ,int b)的调用！" << endl;
&#125;

//函数返回值不可以作为函数重载条件
//int func(double a, int b)
//&#123;
//    cout << "func (double a ,int b)的调用！" << endl;
//&#125;


int main() &#123;

    func();
    func(10);
    func(3.14);
    func(10,3.14);
    func(3.14 , 10);
    
    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="3-3-2-函数重载注意事项"><a href="#3-3-2-函数重载注意事项" class="headerlink" title="3.3.2 函数重载注意事项"></a>3.3.2 函数重载注意事项</h4><ul>
<li>引用作为重载条件</li>
<li>函数重载碰到函数默认参数</li>
</ul>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//函数重载注意事项
//1、引用作为重载条件

void func(int &a)
&#123;
    cout << "func (int &a) 调用 " << endl;
&#125;

void func(const int &a)
&#123;
    cout << "func (const int &a) 调用 " << endl;
&#125;


//2、函数重载碰到函数默认参数

void func2(int a, int b = 10)
&#123;
    cout << "func2(int a, int b = 10) 调用" << endl;
&#125;

void func2(int a)
&#123;
    cout << "func2(int a) 调用" << endl;
&#125;

int main() &#123;
    
    int a = 10;
    func(a); //调用无const
    func(10);//调用有const


    //func2(10); //碰到默认参数产生歧义，需要避免

    system("pause");

    return 0;
&#125;
</code></pre>
<h2 id="4-类和对象"><a href="#4-类和对象" class="headerlink" title="4 类和对象"></a><strong>4</strong> 类和对象</h2><p>C++面向对象的三大特性为：==封装、继承、多态==</p>
<p>C++认为==万事万物都皆为对象==，对象上有其属性和行为</p>
<p><strong>例如：</strong></p>
<p>​    人可以作为对象，属性有姓名、年龄、身高、体重…，行为有走、跑、跳、吃饭、唱歌…</p>
<p>​    车也可以作为对象，属性有轮胎、方向盘、车灯…,行为有载人、放音乐、放空调…</p>
<p>​    具有相同性质的==对象==，我们可以抽象称为==类==，人属于人类，车属于车类</p>
<h3 id="4-1-封装"><a href="#4-1-封装" class="headerlink" title="4.1 封装"></a>4.1 封装</h3><h4 id="4-1-1-封装的意义"><a href="#4-1-1-封装的意义" class="headerlink" title="4.1.1  封装的意义"></a>4.1.1  封装的意义</h4><p>封装是C++面向对象三大特性之一</p>
<p>封装的意义：</p>
<ul>
<li>将属性和行为作为一个整体，表现生活中的事物</li>
<li>将属性和行为加以权限控制</li>
</ul>
<p><strong>封装意义一：</strong></p>
<p>​    在设计类的时候，属性和行为写在一起，表现事物</p>
<p><strong>语法：</strong> <code>class 类名&#123;   访问权限： 属性  / 行为  &#125;;</code></p>
<p><strong>示例1：</strong>设计一个圆类，求圆的周长</p>
<p><strong>示例代码：</strong></p>
<pre class=" language-C++"><code class="language-C++">//圆周率
const double PI = 3.14;

//1、封装的意义
//将属性和行为作为一个整体，用来表现生活中的事物

//封装一个圆类，求圆的周长
//class代表设计一个类，后面跟着的是类名
class Circle
&#123;
public:  //访问权限  公共的权限

    //属性
    int m_r;//半径

    //行为
    //获取到圆的周长
    double calculateZC()
    &#123;
        //2 * pi  * r
        //获取圆的周长
        return  2 * PI * m_r;
    &#125;
&#125;;

int main() &#123;

    //通过圆类，创建圆的对象
    // c1就是一个具体的圆
    Circle c1;
    c1.m_r = 10; //给圆对象的半径 进行赋值操作

    //2 * pi * 10 = = 62.8
    cout << "圆的周长为： " << c1.calculateZC() << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<p><strong>示例2：</strong>设计一个学生类，属性有姓名和学号，可以给姓名和学号赋值，可以显示学生的姓名和学号</p>
<p><strong>示例2代码：</strong></p>
<pre class=" language-C++"><code class="language-C++">//学生类
class Student &#123;
public:
    void setName(string name) &#123;
        m_name = name;
    &#125;
    void setID(int id) &#123;
        m_id = id;
    &#125;

    void showStudent() &#123;
        cout << "name:" << m_name << " ID:" << m_id << endl;
    &#125;
public:
    string m_name;
    int m_id;
&#125;;

int main() &#123;

    Student stu;
    stu.setName("德玛西亚");
    stu.setID(250);
    stu.showStudent();

    system("pause");

    return 0;
&#125;
</code></pre>
<p><strong>封装意义二：</strong></p>
<p>类在设计时，可以把属性和行为放在不同的权限下，加以控制</p>
<p>访问权限有三种：</p>
<ol>
<li>public        公共权限  </li>
<li>protected 保护权限</li>
<li>private      私有权限</li>
</ol>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//三种权限
//公共权限  public     类内可以访问  类外可以访问
//保护权限  protected  类内可以访问  类外不可以访问
//私有权限  private    类内可以访问  类外不可以访问

class Person
&#123;
    //姓名  公共权限
public:
    string m_Name;

    //汽车  保护权限
protected:
    string m_Car;

    //银行卡密码  私有权限
private:
    int m_Password;

public:
    void func()
    &#123;
        m_Name = "张三";
        m_Car = "拖拉机";
        m_Password = 123456;
    &#125;
&#125;;

int main() &#123;

    Person p;
    p.m_Name = "李四";
    //p.m_Car = "奔驰";  //保护权限类外访问不到
    //p.m_Password = 123; //私有权限类外访问不到

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-1-2-struct和class区别"><a href="#4-1-2-struct和class区别" class="headerlink" title="4.1.2 struct和class区别"></a>4.1.2 struct和class区别</h4><p>在C++中 struct和class唯一的<strong>区别</strong>就在于 <strong>默认的访问权限不同</strong></p>
<p>区别：</p>
<ul>
<li>struct 默认权限为公共</li>
<li>class   默认权限为私有</li>
</ul>
<pre class=" language-C++"><code class="language-C++">class C1
&#123;
    int  m_A; //默认是私有权限
&#125;;

struct C2
&#123;
    int m_A;  //默认是公共权限
&#125;;

int main() &#123;

    C1 c1;
    c1.m_A = 10; //错误，访问权限是私有

    C2 c2;
    c2.m_A = 10; //正确，访问权限是公共

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-1-3-成员属性设置为私有"><a href="#4-1-3-成员属性设置为私有" class="headerlink" title="4.1.3 成员属性设置为私有"></a>4.1.3 成员属性设置为私有</h4><p><strong>优点1：</strong>将所有成员属性设置为私有，可以自己控制读写权限</p>
<p><strong>优点2：</strong>对于写权限，我们可以检测数据的有效性</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
public:

    //姓名设置可读可写
    void setName(string name) &#123;
        m_Name = name;
    &#125;
    string getName()
    &#123;
        return m_Name;
    &#125;


    //获取年龄 
    int getAge() &#123;
        return m_Age;
    &#125;
    //设置年龄
    void setAge(int age) &#123;
        if (age < 0 || age > 150) &#123;
            cout << "你个老妖精!" << endl;
            return;
        &#125;
        m_Age = age;
    &#125;

    //情人设置为只写
    void setLover(string lover) &#123;
        m_Lover = lover;
    &#125;

private:
    string m_Name; //可读可写  姓名
    
    int m_Age; //只读  年龄

    string m_Lover; //只写  情人
&#125;;


int main() &#123;

    Person p;
    //姓名设置
    p.setName("张三");
    cout << "姓名： " << p.getName() << endl;

    //年龄设置
    p.setAge(50);
    cout << "年龄： " << p.getAge() << endl;

    //情人设置
    p.setLover("苍井");
    //cout << "情人： " << p.m_Lover << endl;  //只写属性，不可以读取

    system("pause");

    return 0;
&#125;
</code></pre>
<p><strong>练习案例1：设计立方体类</strong></p>
<p>设计立方体类(Cube)</p>
<p>求出立方体的面积和体积</p>
<p>分别用全局函数和成员函数判断两个立方体是否相等。</p>












<p><strong>练习案例2：点和圆的关系</strong></p>
<p>设计一个圆形类（Circle），和一个点类（Point），计算点和圆的关系。</p>








<h3 id="4-2-对象的初始化和清理"><a href="#4-2-对象的初始化和清理" class="headerlink" title="4.2 对象的初始化和清理"></a>4.2 对象的初始化和清理</h3><ul>
<li> 生活中我们买的电子产品都基本会有出厂设置，在某一天我们不用时候也会删除一些自己信息数据保证安全</li>
<li> C++中的面向对象来源于生活，每个对象也都会有初始设置以及 对象销毁前的清理数据的设置。</li>
</ul>
<h4 id="4-2-1-构造函数和析构函数"><a href="#4-2-1-构造函数和析构函数" class="headerlink" title="4.2.1 构造函数和析构函数"></a>4.2.1 构造函数和析构函数</h4><p>对象的<strong>初始化和清理</strong>也是两个非常重要的安全问题</p>
<p>​    一个对象或者变量没有初始状态，对其使用后果是未知</p>
<p>​    同样的使用完一个对象或变量，没有及时清理，也会造成一定的安全问题</p>
<p>c++利用了<strong>构造函数</strong>和<strong>析构函数</strong>解决上述问题，这两个函数将会被编译器自动调用，完成对象初始化和清理工作。</p>
<p>对象的初始化和清理工作是编译器强制要我们做的事情，因此如果<strong>我们不提供构造和析构，编译器会提供</strong></p>
<p><strong>编译器提供的构造函数和析构函数是空实现。</strong></p>
<ul>
<li>构造函数：主要作用在于创建对象时为对象的成员属性赋值，构造函数由编译器自动调用，无须手动调用。</li>
<li>析构函数：主要作用在于对象<strong>销毁前</strong>系统自动调用，执行一些清理工作。</li>
</ul>
<p><strong>构造函数语法：</strong><code>类名()&#123;&#125;</code></p>
<ol>
<li>构造函数，没有返回值也不写void</li>
<li>函数名称与类名相同</li>
<li>构造函数可以有参数，因此可以发生重载</li>
<li>程序在调用对象时候会自动调用构造，无须手动调用,而且只会调用一次</li>
</ol>
<p><strong>析构函数语法：</strong> <code>~类名()&#123;&#125;</code></p>
<ol>
<li>析构函数，没有返回值也不写void</li>
<li>函数名称与类名相同,在名称前加上符号  ~</li>
<li>析构函数不可以有参数，因此不可以发生重载</li>
<li>程序在对象销毁前会自动调用析构，无须手动调用,而且只会调用一次</li>
</ol>
<pre class=" language-C++"><code class="language-C++">class Person
&#123;
public:
    //构造函数
    Person()
    &#123;
        cout << "Person的构造函数调用" << endl;
    &#125;
    //析构函数
    ~Person()
    &#123;
        cout << "Person的析构函数调用" << endl;
    &#125;

&#125;;

void test01()
&#123;
    Person p;
&#125;

int main() &#123;
    
    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-2-2-构造函数的分类及调用"><a href="#4-2-2-构造函数的分类及调用" class="headerlink" title="4.2.2 构造函数的分类及调用"></a>4.2.2 构造函数的分类及调用</h4><p>两种分类方式：</p>
<p>​    按参数分为： 有参构造和无参构造</p>
<p>​    按类型分为： 普通构造和拷贝构造</p>
<p>三种调用方式：</p>
<p>​    括号法</p>
<p>​    显示法</p>
<p>​    隐式转换法</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//1、构造函数分类
// 按照参数分类分为 有参和无参构造   无参又称为默认构造函数
// 按照类型分类分为 普通构造和拷贝构造

class Person &#123;
public:
    //无参（默认）构造函数
    Person() &#123;
        cout << "无参构造函数!" << endl;
    &#125;
    //有参构造函数
    Person(int a) &#123;
        age = a;
        cout << "有参构造函数!" << endl;
    &#125;
    //拷贝构造函数
    Person(const Person& p) &#123;
        age = p.age;
        cout << "拷贝构造函数!" << endl;
    &#125;
    //析构函数
    ~Person() &#123;
        cout << "析构函数!" << endl;
    &#125;
public:
    int age;
&#125;;

//2、构造函数的调用
//调用无参构造函数
void test01() &#123;
    Person p; //调用无参构造函数
&#125;

//调用有参的构造函数
void test02() &#123;

    //2.1  括号法，常用
    Person p1(10);
    //注意1：调用无参构造函数不能加括号，如果加了编译器认为这是一个函数声明
    //Person p2();

    //2.2 显式法
    Person p2 = Person(10); 
    Person p3 = Person(p2);
    //Person(10)单独写就是匿名对象  当前行结束之后，马上析构

    //2.3 隐式转换法
    Person p4 = 10; // Person p4 = Person(10); 
    Person p5 = p4; // Person p5 = Person(p4); 

    //注意2：不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
    //Person p5(p4);
&#125;

int main() &#123;

    test01();
    //test02();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-2-3-拷贝构造函数调用时机"><a href="#4-2-3-拷贝构造函数调用时机" class="headerlink" title="4.2.3 拷贝构造函数调用时机"></a>4.2.3 拷贝构造函数调用时机</h4><p>C++中拷贝构造函数调用时机通常有三种情况</p>
<ul>
<li>使用一个已经创建完毕的对象来初始化一个新对象</li>
<li>值传递的方式给函数参数传值</li>
<li>以值方式返回局部对象</li>
</ul>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
public:
    Person() &#123;
        cout << "无参构造函数!" << endl;
        mAge = 0;
    &#125;
    Person(int age) &#123;
        cout << "有参构造函数!" << endl;
        mAge = age;
    &#125;
    Person(const Person& p) &#123;
        cout << "拷贝构造函数!" << endl;
        mAge = p.mAge;
    &#125;
    //析构函数在释放内存之前调用
    ~Person() &#123;
        cout << "析构函数!" << endl;
    &#125;
public:
    int mAge;
&#125;;

//1. 使用一个已经创建完毕的对象来初始化一个新对象
void test01() &#123;

    Person man(100); //p对象已经创建完毕
    Person newman(man); //调用拷贝构造函数
    Person newman2 = man; //拷贝构造

    //Person newman3;
    //newman3 = man; //不是调用拷贝构造函数，赋值操作
&#125;

//2. 值传递的方式给函数参数传值
//相当于Person p1 = p;
void doWork(Person p1) &#123;&#125;
void test02() &#123;
    Person p; //无参构造函数
    doWork(p);
&#125;

//3. 以值方式返回局部对象
Person doWork2()
&#123;
    Person p1;
    cout << (int *)&p1 << endl;
    return p1;
&#125;

void test03()
&#123;
    Person p = doWork2();
    cout << (int *)&p << endl;
&#125;


int main() &#123;

    //test01();
    //test02();
    test03();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-2-4-构造函数调用规则"><a href="#4-2-4-构造函数调用规则" class="headerlink" title="4.2.4 构造函数调用规则"></a>4.2.4 构造函数调用规则</h4><p>默认情况下，c++编译器至少给一个类添加3个函数</p>
<p>1．默认构造函数(无参，函数体为空)</p>
<p>2．默认析构函数(无参，函数体为空)</p>
<p>3．默认拷贝构造函数，对属性进行值拷贝</p>
<p>构造函数调用规则如下：</p>
<ul>
<li>如果用户定义有参构造函数，c++不在提供默认无参构造，但是会提供默认拷贝构造</li>
</ul>
<ul>
<li>如果用户定义拷贝构造函数，c++不会再提供其他构造函数</li>
</ul>
<p>示例：</p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
public:
    //无参（默认）构造函数
    Person() &#123;
        cout << "无参构造函数!" << endl;
    &#125;
    //有参构造函数
    Person(int a) &#123;
        age = a;
        cout << "有参构造函数!" << endl;
    &#125;
    //拷贝构造函数
    Person(const Person& p) &#123;
        age = p.age;
        cout << "拷贝构造函数!" << endl;
    &#125;
    //析构函数
    ~Person() &#123;
        cout << "析构函数!" << endl;
    &#125;
public:
    int age;
&#125;;

void test01()
&#123;
    Person p1(18);
    //如果不写拷贝构造，编译器会自动添加拷贝构造，并且做浅拷贝操作
    Person p2(p1);

    cout << "p2的年龄为： " << p2.age << endl;
&#125;

void test02()
&#123;
    //如果用户提供有参构造，编译器不会提供默认构造，会提供拷贝构造
    Person p1; //此时如果用户自己没有提供默认构造，会出错
    Person p2(10); //用户提供的有参
    Person p3(p2); //此时如果用户没有提供拷贝构造，编译器会提供

    //如果用户提供拷贝构造，编译器不会提供其他构造函数
    Person p4; //此时如果用户自己没有提供默认构造，会出错
    Person p5(10); //此时如果用户自己没有提供有参，会出错
    Person p6(p5); //用户自己提供拷贝构造
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-2-5-深拷贝与浅拷贝"><a href="#4-2-5-深拷贝与浅拷贝" class="headerlink" title="4.2.5 深拷贝与浅拷贝"></a>4.2.5 深拷贝与浅拷贝</h4><p>深浅拷贝是面试经典问题，也是常见的一个坑</p>
<p>浅拷贝：简单的赋值拷贝操作</p>
<p>深拷贝：在堆区重新申请空间，进行拷贝操作</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
public:
    //无参（默认）构造函数
    Person() &#123;
        cout << "无参构造函数!" << endl;
    &#125;
    //有参构造函数
    Person(int age ,int height) &#123;
        
        cout << "有参构造函数!" << endl;

        m_age = age;
        m_height = new int(height);
        
    &#125;
    //拷贝构造函数  
    Person(const Person& p) &#123;
        cout << "拷贝构造函数!" << endl;
        //如果不利用深拷贝在堆区创建新内存，会导致浅拷贝带来的重复释放堆区问题
        m_age = p.m_age;
        m_height = new int(*p.m_height);
        
    &#125;

    //析构函数
    ~Person() &#123;
        cout << "析构函数!" << endl;
        if (m_height != NULL)
        &#123;
            delete m_height;
        &#125;
    &#125;
public:
    int m_age;
    int* m_height;
&#125;;

void test01()
&#123;
    Person p1(18, 180);

    Person p2(p1);

    cout << "p1的年龄： " << p1.m_age << " 身高： " << *p1.m_height << endl;

    cout << "p2的年龄： " << p2.m_age << " 身高： " << *p2.m_height << endl;
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结：如果属性有在堆区开辟的，一定要自己提供拷贝构造函数，防止浅拷贝带来的问题</p>
</blockquote>
<h4 id="4-2-6-初始化列表"><a href="#4-2-6-初始化列表" class="headerlink" title="4.2.6 初始化列表"></a>4.2.6 初始化列表</h4><p><strong>作用：</strong></p>
<p>C++提供了初始化列表语法，用来初始化属性</p>
<p><strong>语法：</strong><code>构造函数()：属性1(值1),属性2（值2）... &#123;&#125;</code></p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
public:

    ////传统方式初始化
    //Person(int a, int b, int c) &#123;
    //    m_A = a;
    //    m_B = b;
    //    m_C = c;
    //&#125;

    //初始化列表方式初始化
    Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) &#123;&#125;
    void PrintPerson() &#123;
        cout << "mA:" << m_A << endl;
        cout << "mB:" << m_B << endl;
        cout << "mC:" << m_C << endl;
    &#125;
private:
    int m_A;
    int m_B;
    int m_C;
&#125;;

int main() &#123;

    Person p(1, 2, 3);
    p.PrintPerson();


    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-2-7-类对象作为类成员"><a href="#4-2-7-类对象作为类成员" class="headerlink" title="4.2.7 类对象作为类成员"></a>4.2.7 类对象作为类成员</h4><p>C++类中的成员可以是另一个类的对象，我们称该成员为 对象成员</p>
<p>例如：</p>
<pre class=" language-C++"><code class="language-C++">class A &#123;&#125;
class B
&#123;
    A a；
&#125;
</code></pre>
<p>B类中有对象A作为成员，A为对象成员</p>
<p>那么当创建B对象时，A与B的构造和析构的顺序是谁先谁后？</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Phone
&#123;
public:
    Phone(string name)
    &#123;
        m_PhoneName = name;
        cout << "Phone构造" << endl;
    &#125;

    ~Phone()
    &#123;
        cout << "Phone析构" << endl;
    &#125;

    string m_PhoneName;

&#125;;


class Person
&#123;
public:

    //初始化列表可以告诉编译器调用哪一个构造函数
    Person(string name, string pName) :m_Name(name), m_Phone(pName)
    &#123;
        cout << "Person构造" << endl;
    &#125;

    ~Person()
    &#123;
        cout << "Person析构" << endl;
    &#125;

    void playGame()
    &#123;
        cout << m_Name << " 使用" << m_Phone.m_PhoneName << " 牌手机! " << endl;
    &#125;

    string m_Name;
    Phone m_Phone;

&#125;;
void test01()
&#123;
    //当类中成员是其他类对象时，我们称该成员为 对象成员
    //构造的顺序是 ：先调用对象成员的构造，再调用本类构造
    //析构顺序与构造相反
    Person p("张三" , "苹果X");
    p.playGame();

&#125;


int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-2-8-静态成员"><a href="#4-2-8-静态成员" class="headerlink" title="4.2.8 静态成员"></a>4.2.8 静态成员</h4><p>静态成员就是在成员变量和成员函数前加上关键字static，称为静态成员</p>
<p>静态成员分为：</p>
<ul>
<li>静态成员变量<ul>
<li> 所有对象共享同一份数据</li>
<li> 在编译阶段分配内存</li>
<li> 类内声明，类外初始化</li>
</ul>
</li>
<li>静态成员函数<ul>
<li> 所有对象共享同一个函数</li>
<li> 静态成员函数只能访问静态成员变量</li>
</ul>
</li>
</ul>
<p><strong>示例1 ：</strong>静态成员变量</p>
<pre class=" language-C++"><code class="language-C++">class Person
&#123;
    
public:

    static int m_A; //静态成员变量

    //静态成员变量特点：
    //1 在编译阶段分配内存
    //2 类内声明，类外初始化
    //3 所有对象共享同一份数据

private:
    static int m_B; //静态成员变量也是有访问权限的
&#125;;
int Person::m_A = 10;
int Person::m_B = 10;

void test01()
&#123;
    //静态成员变量两种访问方式

    //1、通过对象
    Person p1;
    p1.m_A = 100;
    cout << "p1.m_A = " << p1.m_A << endl;

    Person p2;
    p2.m_A = 200;
    cout << "p1.m_A = " << p1.m_A << endl; //共享同一份数据
    cout << "p2.m_A = " << p2.m_A << endl;

    //2、通过类名
    cout << "m_A = " << Person::m_A << endl;


    //cout << "m_B = " << Person::m_B << endl; //私有权限访问不到
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p><strong>示例2：</strong>静态成员函数</p>
<pre class=" language-C++"><code class="language-C++">class Person
&#123;

public:

    //静态成员函数特点：
    //1 程序共享一个函数
    //2 静态成员函数只能访问静态成员变量
    
    static void func()
    &#123;
        cout << "func调用" << endl;
        m_A = 100;
        //m_B = 100; //错误，不可以访问非静态成员变量
    &#125;

    static int m_A; //静态成员变量
    int m_B; // 
private:

    //静态成员函数也是有访问权限的
    static void func2()
    &#123;
        cout << "func2调用" << endl;
    &#125;
&#125;;
int Person::m_A = 10;


void test01()
&#123;
    //静态成员变量两种访问方式

    //1、通过对象
    Person p1;
    p1.func();

    //2、通过类名
    Person::func();


    //Person::func2(); //私有权限访问不到
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h3 id="4-3-C-对象模型和this指针"><a href="#4-3-C-对象模型和this指针" class="headerlink" title="4.3 C++对象模型和this指针"></a>4.3 C++对象模型和this指针</h3><h4 id="4-3-1-成员变量和成员函数分开存储"><a href="#4-3-1-成员变量和成员函数分开存储" class="headerlink" title="4.3.1 成员变量和成员函数分开存储"></a>4.3.1 成员变量和成员函数分开存储</h4><p>在C++中，类内的成员变量和成员函数分开存储</p>
<p>只有非静态成员变量才属于类的对象上</p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
public:
    Person() &#123;
        mA = 0;
    &#125;
    //非静态成员变量占对象空间
    int mA;
    //静态成员变量不占对象空间
    static int mB; 
    //函数也不占对象空间，所有函数共享一个函数实例
    void func() &#123;
        cout << "mA:" << this->mA << endl;
    &#125;
    //静态成员函数也不占对象空间
    static void sfunc() &#123;
    &#125;
&#125;;

int main() &#123;

    cout << sizeof(Person) << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-3-2-this指针概念"><a href="#4-3-2-this指针概念" class="headerlink" title="4.3.2 this指针概念"></a>4.3.2 this指针概念</h4><p>通过4.3.1我们知道在C++中成员变量和成员函数是分开存储的</p>
<p>每一个非静态成员函数只会诞生一份函数实例，也就是说多个同类型的对象会共用一块代码</p>
<p>那么问题是：这一块代码是如何区分那个对象调用自己的呢？</p>
<p>c++通过提供特殊的对象指针，this指针，解决上述问题。<strong>this指针指向被调用的成员函数所属的对象</strong></p>
<p>this指针是隐含每一个非静态成员函数内的一种指针</p>
<p>this指针不需要定义，直接使用即可</p>
<p>this指针的用途：</p>
<ul>
<li> 当形参和成员变量同名时，可用this指针来区分</li>
<li> 在类的非静态成员函数中返回对象本身，可使用return *this</li>
</ul>
<pre class=" language-C++"><code class="language-C++">class Person
&#123;
public:

    Person(int age)
    &#123;
        //1、当形参和成员变量同名时，可用this指针来区分
        this->age = age;
    &#125;

    Person& PersonAddPerson(Person p)
    &#123;
        this->age += p.age;
        //返回对象本身
        return *this;
    &#125;

    int age;
&#125;;

void test01()
&#123;
    Person p1(10);
    cout << "p1.age = " << p1.age << endl;

    Person p2(10);
    p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);
    cout << "p2.age = " << p2.age << endl;
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-3-3-空指针访问成员函数"><a href="#4-3-3-空指针访问成员函数" class="headerlink" title="4.3.3 空指针访问成员函数"></a>4.3.3 空指针访问成员函数</h4><p>C++中空指针也是可以调用成员函数的，但是也要注意有没有用到this指针</p>
<p>如果用到this指针，需要加以判断保证代码的健壮性</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//空指针访问成员函数
class Person &#123;
public:

    void ShowClassName() &#123;
        cout << "我是Person类!" << endl;
    &#125;

    void ShowPerson() &#123;
        if (this == NULL) &#123;
            return;
        &#125;
        cout << mAge << endl;
    &#125;

public:
    int mAge;
&#125;;

void test01()
&#123;
    Person * p = NULL;
    p->ShowClassName(); //空指针，可以调用成员函数
    p->ShowPerson();  //但是如果成员函数中用到了this指针，就不可以了
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-3-4-const修饰成员函数"><a href="#4-3-4-const修饰成员函数" class="headerlink" title="4.3.4 const修饰成员函数"></a>4.3.4 const修饰成员函数</h4><p><strong>常函数：</strong></p>
<ul>
<li>成员函数后加const后我们称为这个函数为<strong>常函数</strong></li>
<li>常函数内不可以修改成员属性</li>
<li>成员属性声明时加关键字mutable后，在常函数中依然可以修改</li>
</ul>
<p><strong>常对象：</strong></p>
<ul>
<li>声明对象前加const称该对象为常对象</li>
<li>常对象只能调用常函数</li>
</ul>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
public:
    Person() &#123;
        m_A = 0;
        m_B = 0;
    &#125;

    //this指针的本质是一个指针常量，指针的指向不可修改
    //如果想让指针指向的值也不可以修改，需要声明常函数
    void ShowPerson() const &#123;
        //const Type* const pointer;
        //this = NULL; //不能修改指针的指向 Person* const this;
        //this->mA = 100; //但是this指针指向的对象的数据是可以修改的

        //const修饰成员函数，表示指针指向的内存空间的数据不能修改，除了mutable修饰的变量
        this->m_B = 100;
    &#125;

    void MyFunc() const &#123;
        //mA = 10000;
    &#125;

public:
    int m_A;
    mutable int m_B; //可修改 可变的
&#125;;


//const修饰对象  常对象
void test01() &#123;

    const Person person; //常量对象  
    cout << person.m_A << endl;
    //person.mA = 100; //常对象不能修改成员变量的值,但是可以访问
    person.m_B = 100; //但是常对象可以修改mutable修饰成员变量

    //常对象访问成员函数
    person.MyFunc(); //常对象不能调用const的函数

&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h3 id="4-4-友元"><a href="#4-4-友元" class="headerlink" title="4.4 友元"></a>4.4 友元</h3><p>生活中你的家有客厅(Public)，有你的卧室(Private)</p>
<p>客厅所有来的客人都可以进去，但是你的卧室是私有的，也就是说只有你能进去</p>
<p>但是呢，你也可以允许你的好闺蜜好基友进去。</p>
<p>在程序里，有些私有属性 也想让类外特殊的一些函数或者类进行访问，就需要用到友元的技术</p>
<p>友元的目的就是让一个函数或者类 访问另一个类中私有成员</p>
<p>友元的关键字为  ==friend==</p>
<p>友元的三种实现</p>
<ul>
<li>全局函数做友元</li>
<li>类做友元</li>
<li>成员函数做友元</li>
</ul>
<h4 id="4-4-1-全局函数做友元"><a href="#4-4-1-全局函数做友元" class="headerlink" title="4.4.1 全局函数做友元"></a>4.4.1 全局函数做友元</h4><pre class=" language-C++"><code class="language-C++">class Building
&#123;
    //告诉编译器 goodGay全局函数 是 Building类的好朋友，可以访问类中的私有内容
    friend void goodGay(Building * building);

public:

    Building()
    &#123;
        this->m_SittingRoom = "客厅";
        this->m_BedRoom = "卧室";
    &#125;


public:
    string m_SittingRoom; //客厅

private:
    string m_BedRoom; //卧室
&#125;;


void goodGay(Building * building)
&#123;
    cout << "好基友正在访问： " << building->m_SittingRoom << endl;
    cout << "好基友正在访问： " << building->m_BedRoom << endl;
&#125;


void test01()
&#123;
    Building b;
    goodGay(&b);
&#125;

int main()&#123;

    test01();

    system("pause");
    return 0;
&#125;
</code></pre>
<h4 id="4-4-2-类做友元"><a href="#4-4-2-类做友元" class="headerlink" title="4.4.2 类做友元"></a>4.4.2 类做友元</h4><pre class=" language-C++"><code class="language-C++">class Building;
class goodGay
&#123;
public:

    goodGay();
    void visit();

private:
    Building *building;
&#125;;


class Building
&#123;
    //告诉编译器 goodGay类是Building类的好朋友，可以访问到Building类中私有内容
    friend class goodGay;

public:
    Building();

public:
    string m_SittingRoom; //客厅
private:
    string m_BedRoom;//卧室
&#125;;

Building::Building()
&#123;
    this->m_SittingRoom = "客厅";
    this->m_BedRoom = "卧室";
&#125;

goodGay::goodGay()
&#123;
    building = new Building;
&#125;

void goodGay::visit()
&#123;
    cout << "好基友正在访问" << building->m_SittingRoom << endl;
    cout << "好基友正在访问" << building->m_BedRoom << endl;
&#125;

void test01()
&#123;
    goodGay gg;
    gg.visit();

&#125;

int main()&#123;

    test01();

    system("pause");
    return 0;
&#125;
</code></pre>
<h4 id="4-4-3-成员函数做友元"><a href="#4-4-3-成员函数做友元" class="headerlink" title="4.4.3 成员函数做友元"></a>4.4.3 成员函数做友元</h4><pre class=" language-C++"><code class="language-C++">
class Building;
class goodGay
&#123;
public:

    goodGay();
    void visit(); //只让visit函数作为Building的好朋友，可以发访问Building中私有内容
    void visit2(); 

private:
    Building *building;
&#125;;


class Building
&#123;
    //告诉编译器  goodGay类中的visit成员函数 是Building好朋友，可以访问私有内容
    friend void goodGay::visit();

public:
    Building();

public:
    string m_SittingRoom; //客厅
private:
    string m_BedRoom;//卧室
&#125;;

Building::Building()
&#123;
    this->m_SittingRoom = "客厅";
    this->m_BedRoom = "卧室";
&#125;

goodGay::goodGay()
&#123;
    building = new Building;
&#125;

void goodGay::visit()
&#123;
    cout << "好基友正在访问" << building->m_SittingRoom << endl;
    cout << "好基友正在访问" << building->m_BedRoom << endl;
&#125;

void goodGay::visit2()
&#123;
    cout << "好基友正在访问" << building->m_SittingRoom << endl;
    //cout << "好基友正在访问" << building->m_BedRoom << endl;
&#125;

void test01()
&#123;
    goodGay  gg;
    gg.visit();

&#125;

int main()&#123;
    
    test01();

    system("pause");
    return 0;
&#125;
</code></pre>
<h3 id="4-5-运算符重载"><a href="#4-5-运算符重载" class="headerlink" title="4.5 运算符重载"></a>4.5 运算符重载</h3><p>运算符重载概念：对已有的运算符重新进行定义，赋予其另一种功能，以适应不同的数据类型</p>
<h4 id="4-5-1-加号运算符重载"><a href="#4-5-1-加号运算符重载" class="headerlink" title="4.5.1 加号运算符重载"></a>4.5.1 加号运算符重载</h4><p>作用：实现两个自定义数据类型相加的运算</p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
public:
    Person() &#123;&#125;;
    Person(int a, int b)
    &#123;
        this->m_A = a;
        this->m_B = b;
    &#125;
    //成员函数实现 + 号运算符重载
    Person operator+(const Person& p) &#123;
        Person temp;
        temp.m_A = this->m_A + p.m_A;
        temp.m_B = this->m_B + p.m_B;
        return temp;
    &#125;


public:
    int m_A;
    int m_B;
&#125;;

//全局函数实现 + 号运算符重载
//Person operator+(const Person& p1, const Person& p2) &#123;
//    Person temp(0, 0);
//    temp.m_A = p1.m_A + p2.m_A;
//    temp.m_B = p1.m_B + p2.m_B;
//    return temp;
//&#125;

//运算符重载 可以发生函数重载 
Person operator+(const Person& p2, int val)  
&#123;
    Person temp;
    temp.m_A = p2.m_A + val;
    temp.m_B = p2.m_B + val;
    return temp;
&#125;

void test() &#123;

    Person p1(10, 10);
    Person p2(20, 20);

    //成员函数方式
    Person p3 = p2 + p1;  //相当于 p2.operaor+(p1)
    cout << "mA:" << p3.m_A << " mB:" << p3.m_B << endl;


    Person p4 = p3 + 10; //相当于 operator+(p3,10)
    cout << "mA:" << p4.m_A << " mB:" << p4.m_B << endl;

&#125;

int main() &#123;

    test();

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结1：对于内置的数据类型的表达式的的运算符是不可能改变的</p>
</blockquote>
<blockquote>
<p>总结2：不要滥用运算符重载</p>
</blockquote>
<h4 id="4-5-2-左移运算符重载"><a href="#4-5-2-左移运算符重载" class="headerlink" title="4.5.2 左移运算符重载"></a>4.5.2 左移运算符重载</h4><p>作用：可以输出自定义数据类型</p>
<pre class=" language-C++"><code class="language-C++">class Person &#123;
    friend ostream& operator<<(ostream& out, Person& p);

public:

    Person(int a, int b)
    &#123;
        this->m_A = a;
        this->m_B = b;
    &#125;

    //成员函数 实现不了  p << cout 不是我们想要的效果
    //void operator<<(Person& p)&#123;
    //&#125;

private:
    int m_A;
    int m_B;
&#125;;

//全局函数实现左移重载
//ostream对象只能有一个
ostream& operator<<(ostream& out, Person& p) &#123;
    out << "a:" << p.m_A << " b:" << p.m_B;
    return out;
&#125;

void test() &#123;

    Person p1(10, 20);

    cout << p1 << "hello world" << endl; //链式编程
&#125;

int main() &#123;

    test();

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结：重载左移运算符配合友元可以实现输出自定义数据类型</p>
</blockquote>
<h4 id="4-5-3-递增运算符重载"><a href="#4-5-3-递增运算符重载" class="headerlink" title="4.5.3 递增运算符重载"></a>4.5.3 递增运算符重载</h4><p>作用： 通过重载递增运算符，实现自己的整型数据</p>
<pre class=" language-C++"><code class="language-C++">
class MyInteger &#123;

    friend ostream& operator<<(ostream& out, MyInteger myint);

public:
    MyInteger() &#123;
        m_Num = 0;
    &#125;
    //前置++
    MyInteger& operator++() &#123;
        //先++
        m_Num++;
        //再返回
        return *this;
    &#125;

    //后置++
    MyInteger operator++(int) &#123;
        //先返回
        MyInteger temp = *this; //记录当前本身的值，然后让本身的值加1，但是返回的是以前的值，达到先返回后++；
        m_Num++;
        return temp;
    &#125;

private:
    int m_Num;
&#125;;


ostream& operator<<(ostream& out, MyInteger myint) &#123;
    out << myint.m_Num;
    return out;
&#125;


//前置++ 先++ 再返回
void test01() &#123;
    MyInteger myInt;
    cout << ++myInt << endl;
    cout << myInt << endl;
&#125;

//后置++ 先返回 再++
void test02() &#123;

    MyInteger myInt;
    cout << myInt++ << endl;
    cout << myInt << endl;
&#125;

int main() &#123;

    test01();
    //test02();

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结： 前置递增返回引用，后置递增返回值</p>
</blockquote>
<h4 id="4-5-4-赋值运算符重载"><a href="#4-5-4-赋值运算符重载" class="headerlink" title="4.5.4 赋值运算符重载"></a>4.5.4 赋值运算符重载</h4><p>c++编译器至少给一个类添加4个函数</p>
<ol>
<li>默认构造函数(无参，函数体为空)</li>
<li>默认析构函数(无参，函数体为空)</li>
<li>默认拷贝构造函数，对属性进行值拷贝</li>
<li>赋值运算符 operator=, 对属性进行值拷贝</li>
</ol>
<p>如果类中有属性指向堆区，做赋值操作时也会出现深浅拷贝问题</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Person
&#123;
public:

    Person(int age)
    &#123;
        //将年龄数据开辟到堆区
        m_Age = new int(age);
    &#125;

    //重载赋值运算符 
    Person& operator=(Person &p)
    &#123;
        if (m_Age != NULL)
        &#123;
            delete m_Age;
            m_Age = NULL;
        &#125;
        //编译器提供的代码是浅拷贝
        //m_Age = p.m_Age;

        //提供深拷贝 解决浅拷贝的问题
        m_Age = new int(*p.m_Age);

        //返回自身
        return *this;
    &#125;


    ~Person()
    &#123;
        if (m_Age != NULL)
        &#123;
            delete m_Age;
            m_Age = NULL;
        &#125;
    &#125;

    //年龄的指针
    int *m_Age;

&#125;;


void test01()
&#123;
    Person p1(18);

    Person p2(20);

    Person p3(30);

    p3 = p2 = p1; //赋值操作

    cout << "p1的年龄为：" << *p1.m_Age << endl;

    cout << "p2的年龄为：" << *p2.m_Age << endl;

    cout << "p3的年龄为：" << *p3.m_Age << endl;
&#125;

int main() &#123;

    test01();

    //int a = 10;
    //int b = 20;
    //int c = 30;

    //c = b = a;
    //cout << "a = " << a << endl;
    //cout << "b = " << b << endl;
    //cout << "c = " << c << endl;

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-5-5-关系运算符重载"><a href="#4-5-5-关系运算符重载" class="headerlink" title="4.5.5 关系运算符重载"></a>4.5.5 关系运算符重载</h4><p><strong>作用：</strong>重载关系运算符，可以让两个自定义类型对象进行对比操作</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Person
&#123;
public:
    Person(string name, int age)
    &#123;
        this->m_Name = name;
        this->m_Age = age;
    &#125;;

    bool operator==(Person & p)
    &#123;
        if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
        &#123;
            return true;
        &#125;
        else
        &#123;
            return false;
        &#125;
    &#125;

    bool operator!=(Person & p)
    &#123;
        if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
        &#123;
            return false;
        &#125;
        else
        &#123;
            return true;
        &#125;
    &#125;

    string m_Name;
    int m_Age;
&#125;;

void test01()
&#123;
    //int a = 0;
    //int b = 0;

    Person a("孙悟空", 18);
    Person b("孙悟空", 18);

    if (a == b)
    &#123;
        cout << "a和b相等" << endl;
    &#125;
    else
    &#123;
        cout << "a和b不相等" << endl;
    &#125;

    if (a != b)
    &#123;
        cout << "a和b不相等" << endl;
    &#125;
    else
    &#123;
        cout << "a和b相等" << endl;
    &#125;
&#125;


int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-5-6-函数调用运算符重载"><a href="#4-5-6-函数调用运算符重载" class="headerlink" title="4.5.6 函数调用运算符重载"></a>4.5.6 函数调用运算符重载</h4><ul>
<li>函数调用运算符 ()  也可以重载</li>
<li>由于重载后使用的方式非常像函数的调用，因此称为仿函数</li>
<li>仿函数没有固定写法，非常灵活</li>
</ul>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class MyPrint
&#123;
public:
    void operator()(string text)
    &#123;
        cout << text << endl;
    &#125;

&#125;;
void test01()
&#123;
    //重载的（）操作符 也称为仿函数
    MyPrint myFunc;
    myFunc("hello world");
&#125;


class MyAdd
&#123;
public:
    int operator()(int v1, int v2)
    &#123;
        return v1 + v2;
    &#125;
&#125;;

void test02()
&#123;
    MyAdd add;
    int ret = add(10, 10);
    cout << "ret = " << ret << endl;

    //匿名对象调用  
    cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
&#125;

int main() &#123;

    test01();
    test02();

    system("pause");

    return 0;
&#125;
</code></pre>
<h3 id="4-6-继承"><a href="#4-6-继承" class="headerlink" title="4.6  继承"></a>4.6  继承</h3><p><strong>继承是面向对象三大特性之一</strong></p>
<p>有些类与类之间存在特殊的关系，例如下图中：</p>


<p>我们发现，定义这些类时，下级别的成员除了拥有上一级的共性，还有自己的特性。</p>
<p>这个时候我们就可以考虑利用继承的技术，减少重复代码</p>
<h4 id="4-6-1-继承的基本语法"><a href="#4-6-1-继承的基本语法" class="headerlink" title="4.6.1 继承的基本语法"></a>4.6.1 继承的基本语法</h4><p>例如我们看到很多网站中，都有公共的头部，公共的底部，甚至公共的左侧列表，只有中心内容不同</p>
<p>接下来我们分别利用普通写法和继承的写法来实现网页中的内容，看一下继承存在的意义以及好处</p>
<p><strong>普通实现：</strong></p>
<pre class=" language-C++"><code class="language-C++">//Java页面
class Java 
&#123;
public:
    void header()
    &#123;
        cout << "首页、公开课、登录、注册...（公共头部）" << endl;
    &#125;
    void footer()
    &#123;
        cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
    &#125;
    void left()
    &#123;
        cout << "Java,Python,C++...(公共分类列表)" << endl;
    &#125;
    void content()
    &#123;
        cout << "JAVA学科视频" << endl;
    &#125;
&#125;;
//Python页面
class Python
&#123;
public:
    void header()
    &#123;
        cout << "首页、公开课、登录、注册...（公共头部）" << endl;
    &#125;
    void footer()
    &#123;
        cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
    &#125;
    void left()
    &#123;
        cout << "Java,Python,C++...(公共分类列表)" << endl;
    &#125;
    void content()
    &#123;
        cout << "Python学科视频" << endl;
    &#125;
&#125;;
//C++页面
class CPP 
&#123;
public:
    void header()
    &#123;
        cout << "首页、公开课、登录、注册...（公共头部）" << endl;
    &#125;
    void footer()
    &#123;
        cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
    &#125;
    void left()
    &#123;
        cout << "Java,Python,C++...(公共分类列表)" << endl;
    &#125;
    void content()
    &#123;
        cout << "C++学科视频" << endl;
    &#125;
&#125;;

void test01()
&#123;
    //Java页面
    cout << "Java下载视频页面如下： " << endl;
    Java ja;
    ja.header();
    ja.footer();
    ja.left();
    ja.content();
    cout << "--------------------" << endl;

    //Python页面
    cout << "Python下载视频页面如下： " << endl;
    Python py;
    py.header();
    py.footer();
    py.left();
    py.content();
    cout << "--------------------" << endl;

    //C++页面
    cout << "C++下载视频页面如下： " << endl;
    CPP cp;
    cp.header();
    cp.footer();
    cp.left();
    cp.content();

&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p><strong>继承实现：</strong></p>
<pre class=" language-C++"><code class="language-C++">//公共页面
class BasePage
&#123;
public:
    void header()
    &#123;
        cout << "首页、公开课、登录、注册...（公共头部）" << endl;
    &#125;

    void footer()
    &#123;
        cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
    &#125;
    void left()
    &#123;
        cout << "Java,Python,C++...(公共分类列表)" << endl;
    &#125;

&#125;;

//Java页面
class Java : public BasePage
&#123;
public:
    void content()
    &#123;
        cout << "JAVA学科视频" << endl;
    &#125;
&#125;;
//Python页面
class Python : public BasePage
&#123;
public:
    void content()
    &#123;
        cout << "Python学科视频" << endl;
    &#125;
&#125;;
//C++页面
class CPP : public BasePage
&#123;
public:
    void content()
    &#123;
        cout << "C++学科视频" << endl;
    &#125;
&#125;;

void test01()
&#123;
    //Java页面
    cout << "Java下载视频页面如下： " << endl;
    Java ja;
    ja.header();
    ja.footer();
    ja.left();
    ja.content();
    cout << "--------------------" << endl;

    //Python页面
    cout << "Python下载视频页面如下： " << endl;
    Python py;
    py.header();
    py.footer();
    py.left();
    py.content();
    cout << "--------------------" << endl;

    //C++页面
    cout << "C++下载视频页面如下： " << endl;
    CPP cp;
    cp.header();
    cp.footer();
    cp.left();
    cp.content();


&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p><strong>总结：</strong></p>
<p>继承的好处：==可以减少重复的代码==</p>
<p>class A : public B; </p>
<p>A 类称为子类 或 派生类</p>
<p>B 类称为父类 或 基类</p>
<p><strong>派生类中的成员，包含两大部分</strong>：</p>
<p>一类是从基类继承过来的，一类是自己增加的成员。</p>
<p>从基类继承过过来的表现其共性，而新增的成员体现了其个性。</p>
<h4 id="4-6-2-继承方式"><a href="#4-6-2-继承方式" class="headerlink" title="4.6.2 继承方式"></a>4.6.2 继承方式</h4><p>继承的语法：<code>class 子类 : 继承方式  父类</code></p>
<p><strong>继承方式一共有三种：</strong></p>
<ul>
<li>公共继承</li>
<li>保护继承</li>
<li>私有继承</li>
</ul>






<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Base1
&#123;
public: 
    int m_A;
protected:
    int m_B;
private:
    int m_C;
&#125;;

//公共继承
class Son1 :public Base1
&#123;
public:
    void func()
    &#123;
        m_A; //可访问 public权限
        m_B; //可访问 protected权限
        //m_C; //不可访问
    &#125;
&#125;;

void myClass()
&#123;
    Son1 s1;
    s1.m_A; //其他类只能访问到公共权限
&#125;

//保护继承
class Base2
&#123;
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C;
&#125;;
class Son2:protected Base2
&#123;
public:
    void func()
    &#123;
        m_A; //可访问 protected权限
        m_B; //可访问 protected权限
        //m_C; //不可访问
    &#125;
&#125;;
void myClass2()
&#123;
    Son2 s;
    //s.m_A; //不可访问
&#125;

//私有继承
class Base3
&#123;
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C;
&#125;;
class Son3:private Base3
&#123;
public:
    void func()
    &#123;
        m_A; //可访问 private权限
        m_B; //可访问 private权限
        //m_C; //不可访问
    &#125;
&#125;;
class GrandSon3 :public Son3
&#123;
public:
    void func()
    &#123;
        //Son3是私有继承，所以继承Son3的属性在GrandSon3中都无法访问到
        //m_A;
        //m_B;
        //m_C;
    &#125;
&#125;;
</code></pre>
<h4 id="4-6-3-继承中的对象模型"><a href="#4-6-3-继承中的对象模型" class="headerlink" title="4.6.3 继承中的对象模型"></a>4.6.3 继承中的对象模型</h4><p><strong>问题：</strong>从父类继承过来的成员，哪些属于子类对象中？</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Base
&#123;
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C; //私有成员只是被隐藏了，但是还是会继承下去
&#125;;

//公共继承
class Son :public Base
&#123;
public:
    int m_D;
&#125;;

void test01()
&#123;
    cout << "sizeof Son = " << sizeof(Son) << endl;
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p>利用工具查看：</p>




<p>打开工具窗口后，定位到当前CPP文件的盘符</p>
<p>然后输入： cl /d1 reportSingleClassLayout查看的类名   所属文件名</p>
<p>效果如下图：</p>




<blockquote>
<p>结论： 父类中私有成员也是被子类继承下去了，只是由编译器给隐藏后访问不到</p>
</blockquote>
<h4 id="4-6-4-继承中构造和析构顺序"><a href="#4-6-4-继承中构造和析构顺序" class="headerlink" title="4.6.4 继承中构造和析构顺序"></a>4.6.4 继承中构造和析构顺序</h4><p>子类继承父类后，当创建子类对象，也会调用父类的构造函数</p>
<p>问题：父类和子类的构造和析构顺序是谁先谁后？</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Base 
&#123;
public:
    Base()
    &#123;
        cout << "Base构造函数!" << endl;
    &#125;
    ~Base()
    &#123;
        cout << "Base析构函数!" << endl;
    &#125;
&#125;;

class Son : public Base
&#123;
public:
    Son()
    &#123;
        cout << "Son构造函数!" << endl;
    &#125;
    ~Son()
    &#123;
        cout << "Son析构函数!" << endl;
    &#125;

&#125;;


void test01()
&#123;
    //继承中 先调用父类构造函数，再调用子类构造函数，析构顺序与构造相反
    Son s;
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结：继承中 先调用父类构造函数，再调用子类构造函数，析构顺序与构造相反</p>
</blockquote>
<h4 id="4-6-5-继承同名成员处理方式"><a href="#4-6-5-继承同名成员处理方式" class="headerlink" title="4.6.5 继承同名成员处理方式"></a>4.6.5 继承同名成员处理方式</h4><p>问题：当子类与父类出现同名的成员，如何通过子类对象，访问到子类或父类中同名的数据呢？</p>
<ul>
<li>访问子类同名成员   直接访问即可</li>
<li>访问父类同名成员   需要加作用域</li>
</ul>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Base &#123;
public:
    Base()
    &#123;
        m_A = 100;
    &#125;

    void func()
    &#123;
        cout << "Base - func()调用" << endl;
    &#125;

    void func(int a)
    &#123;
        cout << "Base - func(int a)调用" << endl;
    &#125;

public:
    int m_A;
&#125;;


class Son : public Base &#123;
public:
    Son()
    &#123;
        m_A = 200;
    &#125;

    //当子类与父类拥有同名的成员函数，子类会隐藏父类中所有版本的同名成员函数
    //如果想访问父类中被隐藏的同名成员函数，需要加父类的作用域
    void func()
    &#123;
        cout << "Son - func()调用" << endl;
    &#125;
public:
    int m_A;
&#125;;

void test01()
&#123;
    Son s;

    cout << "Son下的m_A = " << s.m_A << endl;
    cout << "Base下的m_A = " << s.Base::m_A << endl;

    s.func();
    s.Base::func();
    s.Base::func(10);

&#125;
int main() &#123;

    test01();

    system("pause");
    return EXIT_SUCCESS;
&#125;
</code></pre>
<p>总结：</p>
<ol>
<li>子类对象可以直接访问到子类中同名成员</li>
<li>子类对象加作用域可以访问到父类同名成员</li>
<li>当子类与父类拥有同名的成员函数，子类会隐藏父类中同名成员函数，加作用域可以访问到父类中同名函数</li>
</ol>
<h4 id="4-6-6-继承同名静态成员处理方式"><a href="#4-6-6-继承同名静态成员处理方式" class="headerlink" title="4.6.6 继承同名静态成员处理方式"></a>4.6.6 继承同名静态成员处理方式</h4><p>问题：继承中同名的静态成员在子类对象上如何进行访问？</p>
<p>静态成员和非静态成员出现同名，处理方式一致</p>
<ul>
<li>访问子类同名成员   直接访问即可</li>
<li>访问父类同名成员   需要加作用域</li>
</ul>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Base &#123;
public:
    static void func()
    &#123;
        cout << "Base - static void func()" << endl;
    &#125;
    static void func(int a)
    &#123;
        cout << "Base - static void func(int a)" << endl;
    &#125;

    static int m_A;
&#125;;

int Base::m_A = 100;

class Son : public Base &#123;
public:
    static void func()
    &#123;
        cout << "Son - static void func()" << endl;
    &#125;
    static int m_A;
&#125;;

int Son::m_A = 200;

//同名成员属性
void test01()
&#123;
    //通过对象访问
    cout << "通过对象访问： " << endl;
    Son s;
    cout << "Son  下 m_A = " << s.m_A << endl;
    cout << "Base 下 m_A = " << s.Base::m_A << endl;

    //通过类名访问
    cout << "通过类名访问： " << endl;
    cout << "Son  下 m_A = " << Son::m_A << endl;
    cout << "Base 下 m_A = " << Son::Base::m_A << endl;
&#125;

//同名成员函数
void test02()
&#123;
    //通过对象访问
    cout << "通过对象访问： " << endl;
    Son s;
    s.func();
    s.Base::func();

    cout << "通过类名访问： " << endl;
    Son::func();
    Son::Base::func();
    //出现同名，子类会隐藏掉父类中所有同名成员函数，需要加作作用域访问
    Son::Base::func(100);
&#125;
int main() &#123;

    //test01();
    test02();

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结：同名静态成员处理方式和非静态处理方式一样，只不过有两种访问的方式（通过对象 和 通过类名）</p>
</blockquote>
<h4 id="4-6-7-多继承语法"><a href="#4-6-7-多继承语法" class="headerlink" title="4.6.7 多继承语法"></a>4.6.7 多继承语法</h4><p>C++允许<strong>一个类继承多个类</strong></p>
<p>语法：<code> class 子类 ：继承方式 父类1 ， 继承方式 父类2...</code></p>
<p>多继承可能会引发父类中有同名成员出现，需要加作用域区分</p>
<p><strong>C++实际开发中不建议用多继承</strong></p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Base1 &#123;
public:
    Base1()
    &#123;
        m_A = 100;
    &#125;
public:
    int m_A;
&#125;;

class Base2 &#123;
public:
    Base2()
    &#123;
        m_A = 200;  //开始是m_B 不会出问题，但是改为mA就会出现不明确
    &#125;
public:
    int m_A;
&#125;;

//语法：class 子类：继承方式 父类1 ，继承方式 父类2 
class Son : public Base2, public Base1 
&#123;
public:
    Son()
    &#123;
        m_C = 300;
        m_D = 400;
    &#125;
public:
    int m_C;
    int m_D;
&#125;;


//多继承容易产生成员同名的情况
//通过使用类名作用域可以区分调用哪一个基类的成员
void test01()
&#123;
    Son s;
    cout << "sizeof Son = " << sizeof(s) << endl;
    cout << s.Base1::m_A << endl;
    cout << s.Base2::m_A << endl;
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结： 多继承中如果父类中出现了同名情况，子类使用时候要加作用域</p>
</blockquote>
<h4 id="4-6-8-菱形继承"><a href="#4-6-8-菱形继承" class="headerlink" title="4.6.8 菱形继承"></a>4.6.8 菱形继承</h4><p><strong>菱形继承概念：</strong></p>
<p>​    两个派生类继承同一个基类</p>
<p>​    又有某个类同时继承者两个派生类</p>
<p>​    这种继承被称为菱形继承，或者钻石继承</p>
<p><strong>典型的菱形继承案例：</strong></p>




<p><strong>菱形继承问题：</strong></p>
<ol>
<li><pre><code>羊继承了动物的数据，驼同样继承了动物的数据，当草泥马使用数据时，就会产生二义性。
</code></pre>
</li>
<li><p>草泥马继承自动物的数据继承了两份，其实我们应该清楚，这份数据我们只需要一份就可以。</p>
</li>
</ol>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Animal
&#123;
public:
    int m_Age;
&#125;;

//继承前加virtual关键字后，变为虚继承
//此时公共的父类Animal称为虚基类
class Sheep : virtual public Animal &#123;&#125;;
class Tuo   : virtual public Animal &#123;&#125;;
class SheepTuo : public Sheep, public Tuo &#123;&#125;;

void test01()
&#123;
    SheepTuo st;
    st.Sheep::m_Age = 100;
    st.Tuo::m_Age = 200;

    cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
    cout << "st.Tuo::m_Age = " <<  st.Tuo::m_Age << endl;
    cout << "st.m_Age = " << st.m_Age << endl;
&#125;


int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p>总结：</p>
<ul>
<li>菱形继承带来的主要问题是子类继承两份相同的数据，导致资源浪费以及毫无意义</li>
<li>利用虚继承可以解决菱形继承问题</li>
</ul>
<h3 id="4-7-多态"><a href="#4-7-多态" class="headerlink" title="4.7  多态"></a>4.7  多态</h3><h4 id="4-7-1-多态的基本概念"><a href="#4-7-1-多态的基本概念" class="headerlink" title="4.7.1 多态的基本概念"></a>4.7.1 多态的基本概念</h4><p><strong>多态是C++面向对象三大特性之一</strong></p>
<p>多态分为两类</p>
<ul>
<li>静态多态: 函数重载 和 运算符重载属于静态多态，复用函数名</li>
<li>动态多态: 派生类和虚函数实现运行时多态</li>
</ul>
<p>静态多态和动态多态区别：</p>
<ul>
<li>静态多态的函数地址早绑定  -  编译阶段确定函数地址</li>
<li>动态多态的函数地址晚绑定  -  运行阶段确定函数地址</li>
</ul>
<p>下面通过案例进行讲解多态</p>
<pre class=" language-C++"><code class="language-C++">class Animal
&#123;
public:
    //Speak函数就是虚函数
    //函数前面加上virtual关键字，变成虚函数，那么编译器在编译的时候就不能确定函数调用了。
    virtual void speak()
    &#123;
        cout << "动物在说话" << endl;
    &#125;
&#125;;

class Cat :public Animal
&#123;
public:
    void speak()
    &#123;
        cout << "小猫在说话" << endl;
    &#125;
&#125;;

class Dog :public Animal
&#123;
public:

    void speak()
    &#123;
        cout << "小狗在说话" << endl;
    &#125;

&#125;;
//我们希望传入什么对象，那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定，那么静态联编
//如果函数地址在运行阶段才能确定，就是动态联编

void DoSpeak(Animal & animal)
&#123;
    animal.speak();
&#125;
//
//多态满足条件： 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用：
//父类指针或引用指向子类对象

void test01()
&#123;
    Cat cat;
    DoSpeak(cat);


    Dog dog;
    DoSpeak(dog);
&#125;


int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p>总结：</p>
<p>多态满足条件</p>
<ul>
<li>有继承关系</li>
<li>子类重写父类中的虚函数</li>
</ul>
<p>多态使用条件</p>
<ul>
<li>父类指针或引用指向子类对象</li>
</ul>
<p>重写：函数返回值类型  函数名 参数列表 完全一致称为重写</p>
<h4 id="4-7-2-多态案例一-计算器类"><a href="#4-7-2-多态案例一-计算器类" class="headerlink" title="4.7.2 多态案例一-计算器类"></a>4.7.2 多态案例一-计算器类</h4><p>案例描述：</p>
<p>分别利用普通写法和多态技术，设计实现两个操作数进行运算的计算器类</p>
<p>多态的优点：</p>
<ul>
<li>代码组织结构清晰</li>
<li>可读性强</li>
<li>利于前期和后期的扩展以及维护</li>
</ul>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//普通实现
class Calculator &#123;
public:
    int getResult(string oper)
    &#123;
        if (oper == "+") &#123;
            return m_Num1 + m_Num2;
        &#125;
        else if (oper == "-") &#123;
            return m_Num1 - m_Num2;
        &#125;
        else if (oper == "*") &#123;
            return m_Num1 * m_Num2;
        &#125;
        //如果要提供新的运算，需要修改源码
    &#125;
public:
    int m_Num1;
    int m_Num2;
&#125;;

void test01()
&#123;
    //普通实现测试
    Calculator c;
    c.m_Num1 = 10;
    c.m_Num2 = 10;
    cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;

    cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl;

    cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl;
&#125;



//多态实现
//抽象计算器类
//多态优点：代码组织结构清晰，可读性强，利于前期和后期的扩展以及维护
class AbstractCalculator
&#123;
public :

    virtual int getResult()
    &#123;
        return 0;
    &#125;

    int m_Num1;
    int m_Num2;
&#125;;

//加法计算器
class AddCalculator :public AbstractCalculator
&#123;
public:
    int getResult()
    &#123;
        return m_Num1 + m_Num2;
    &#125;
&#125;;

//减法计算器
class SubCalculator :public AbstractCalculator
&#123;
public:
    int getResult()
    &#123;
        return m_Num1 - m_Num2;
    &#125;
&#125;;

//乘法计算器
class MulCalculator :public AbstractCalculator
&#123;
public:
    int getResult()
    &#123;
        return m_Num1 * m_Num2;
    &#125;
&#125;;


void test02()
&#123;
    //创建加法计算器
    AbstractCalculator *abc = new AddCalculator;
    abc->m_Num1 = 10;
    abc->m_Num2 = 10;
    cout << abc->m_Num1 << " + " << abc->m_Num2 << " = " << abc->getResult() << endl;
    delete abc;  //用完了记得销毁

    //创建减法计算器
    abc = new SubCalculator;
    abc->m_Num1 = 10;
    abc->m_Num2 = 10;
    cout << abc->m_Num1 << " - " << abc->m_Num2 << " = " << abc->getResult() << endl;
    delete abc;  

    //创建乘法计算器
    abc = new MulCalculator;
    abc->m_Num1 = 10;
    abc->m_Num2 = 10;
    cout << abc->m_Num1 << " * " << abc->m_Num2 << " = " << abc->getResult() << endl;
    delete abc;
&#125;

int main() &#123;

    //test01();

    test02();

    system("pause");

    return 0;
&#125;
</code></pre>
<blockquote>
<p>总结：C++开发提倡利用多态设计程序架构，因为多态优点很多</p>
</blockquote>
<h4 id="4-7-3-纯虚函数和抽象类"><a href="#4-7-3-纯虚函数和抽象类" class="headerlink" title="4.7.3 纯虚函数和抽象类"></a>4.7.3 纯虚函数和抽象类</h4><p>在多态中，通常父类中虚函数的实现是毫无意义的，主要都是调用子类重写的内容</p>
<p>因此可以将虚函数改为<strong>纯虚函数</strong></p>
<p>纯虚函数语法：<code>virtual 返回值类型 函数名 （参数列表）= 0 ;</code></p>
<p>当类中有了纯虚函数，这个类也称为==抽象类==</p>
<p><strong>抽象类特点</strong>：</p>
<ul>
<li>无法实例化对象</li>
<li>子类必须重写抽象类中的纯虚函数，否则也属于抽象类</li>
</ul>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Base
&#123;
public:
    //纯虚函数
    //类中只要有一个纯虚函数就称为抽象类
    //抽象类无法实例化对象
    //子类必须重写父类中的纯虚函数，否则也属于抽象类
    virtual void func() = 0;
&#125;;

class Son :public Base
&#123;
public:
    virtual void func() 
    &#123;
        cout << "func调用" << endl;
    &#125;;
&#125;;

void test01()
&#123;
    Base * base = NULL;
    //base = new Base; // 错误，抽象类无法实例化对象
    base = new Son;
    base->func();
    delete base;//记得销毁
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-7-4-多态案例二-制作饮品"><a href="#4-7-4-多态案例二-制作饮品" class="headerlink" title="4.7.4 多态案例二-制作饮品"></a>4.7.4 多态案例二-制作饮品</h4><p><strong>案例描述：</strong></p>
<p>制作饮品的大致流程为：煮水 -  冲泡 - 倒入杯中 - 加入辅料</p>
<p>利用多态技术实现本案例，提供抽象制作饮品基类，提供子类制作咖啡和茶叶</p>




<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">//抽象制作饮品
class AbstractDrinking &#123;
public:
    //烧水
    virtual void Boil() = 0;
    //冲泡
    virtual void Brew() = 0;
    //倒入杯中
    virtual void PourInCup() = 0;
    //加入辅料
    virtual void PutSomething() = 0;
    //规定流程
    void MakeDrink() &#123;
        Boil();
        Brew();
        PourInCup();
        PutSomething();
    &#125;
&#125;;

//制作咖啡
class Coffee : public AbstractDrinking &#123;
public:
    //烧水
    virtual void Boil() &#123;
        cout << "煮农夫山泉!" << endl;
    &#125;
    //冲泡
    virtual void Brew() &#123;
        cout << "冲泡咖啡!" << endl;
    &#125;
    //倒入杯中
    virtual void PourInCup() &#123;
        cout << "将咖啡倒入杯中!" << endl;
    &#125;
    //加入辅料
    virtual void PutSomething() &#123;
        cout << "加入牛奶!" << endl;
    &#125;
&#125;;

//制作茶水
class Tea : public AbstractDrinking &#123;
public:
    //烧水
    virtual void Boil() &#123;
        cout << "煮自来水!" << endl;
    &#125;
    //冲泡
    virtual void Brew() &#123;
        cout << "冲泡茶叶!" << endl;
    &#125;
    //倒入杯中
    virtual void PourInCup() &#123;
        cout << "将茶水倒入杯中!" << endl;
    &#125;
    //加入辅料
    virtual void PutSomething() &#123;
        cout << "加入枸杞!" << endl;
    &#125;
&#125;;

//业务函数
void DoWork(AbstractDrinking* drink) &#123;
    drink->MakeDrink();
    delete drink;
&#125;

void test01() &#123;
    DoWork(new Coffee);
    cout << "--------------" << endl;
    DoWork(new Tea);
&#125;


int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<h4 id="4-7-5-虚析构和纯虚析构"><a href="#4-7-5-虚析构和纯虚析构" class="headerlink" title="4.7.5 虚析构和纯虚析构"></a>4.7.5 虚析构和纯虚析构</h4><p>多态使用时，如果子类中有属性开辟到堆区，那么父类指针在释放时无法调用到子类的析构代码</p>
<p>解决方式：将父类中的析构函数改为<strong>虚析构</strong>或者<strong>纯虚析构</strong></p>
<p>虚析构和纯虚析构共性：</p>
<ul>
<li>可以解决父类指针释放子类对象</li>
<li>都需要有具体的函数实现</li>
</ul>
<p>虚析构和纯虚析构区别：</p>
<ul>
<li>如果是纯虚析构，该类属于抽象类，无法实例化对象</li>
</ul>
<p>虚析构语法：</p>
<p><code>virtual ~类名()&#123;&#125;</code></p>
<p>纯虚析构语法：</p>
<p><code> virtual ~类名() = 0;</code></p>
<p><code>类名::~类名()&#123;&#125;</code></p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">class Animal &#123;
public:

    Animal()
    &#123;
        cout << "Animal 构造函数调用！" << endl;
    &#125;
    virtual void Speak() = 0;

    //析构函数加上virtual关键字，变成虚析构函数
    //virtual ~Animal()
    //&#123;
    //    cout << "Animal虚析构函数调用！" << endl;
    //&#125;


    virtual ~Animal() = 0;
&#125;;

Animal::~Animal()
&#123;
    cout << "Animal 纯虚析构函数调用！" << endl;
&#125;

//和包含普通纯虚函数的类一样，包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。

class Cat : public Animal &#123;
public:
    Cat(string name)
    &#123;
        cout << "Cat构造函数调用！" << endl;
        m_Name = new string(name);
    &#125;
    virtual void Speak()
    &#123;
        cout << *m_Name <<  "小猫在说话!" << endl;
    &#125;
    ~Cat()
    &#123;
        cout << "Cat析构函数调用!" << endl;
        if (this->m_Name != NULL) &#123;
            delete m_Name;
            m_Name = NULL;
        &#125;
    &#125;

public:
    string *m_Name;
&#125;;

void test01()
&#123;
    Animal *animal = new Cat("Tom");
    animal->Speak();

    //通过父类指针去释放，会导致子类对象可能清理不干净，造成内存泄漏
    //怎么解决？给基类增加一个虚析构函数
    //虚析构函数就是用来解决通过父类指针释放子类对象
    delete animal;
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p>总结：</p>
<p>​    1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象</p>
<p>​    2. 如果子类中没有堆区数据，可以不写为虚析构或纯虚析构</p>
<p>​    3. 拥有纯虚析构函数的类也属于抽象类</p>
<h4 id="4-7-6-多态案例三-电脑组装"><a href="#4-7-6-多态案例三-电脑组装" class="headerlink" title="4.7.6 多态案例三-电脑组装"></a>4.7.6 多态案例三-电脑组装</h4><p><strong>案例描述：</strong></p>
<p>电脑主要组成部件为 CPU（用于计算），显卡（用于显示），内存条（用于存储）</p>
<p>将每个零件封装出抽象基类，并且提供不同的厂商生产不同的零件，例如Intel厂商和Lenovo厂商</p>
<p>创建电脑类提供让电脑工作的函数，并且调用每个零件工作的接口</p>
<p>测试时组装三台不同的电脑进行工作</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">#include<iostream>
using namespace std;

//抽象CPU类
class CPU
&#123;
public:
    //抽象的计算函数
    virtual void calculate() = 0;
&#125;;

//抽象显卡类
class VideoCard
&#123;
public:
    //抽象的显示函数
    virtual void display() = 0;
&#125;;

//抽象内存条类
class Memory
&#123;
public:
    //抽象的存储函数
    virtual void storage() = 0;
&#125;;

//电脑类
class Computer
&#123;
public:
    Computer(CPU * cpu, VideoCard * vc, Memory * mem)
    &#123;
        m_cpu = cpu;
        m_vc = vc;
        m_mem = mem;
    &#125;

    //提供工作的函数
    void work()
    &#123;
        //让零件工作起来，调用接口
        m_cpu->calculate();

        m_vc->display();

        m_mem->storage();
    &#125;

    //提供析构函数 释放3个电脑零件
    ~Computer()
    &#123;

        //释放CPU零件
        if (m_cpu != NULL)
        &#123;
            delete m_cpu;
            m_cpu = NULL;
        &#125;

        //释放显卡零件
        if (m_vc != NULL)
        &#123;
            delete m_vc;
            m_vc = NULL;
        &#125;

        //释放内存条零件
        if (m_mem != NULL)
        &#123;
            delete m_mem;
            m_mem = NULL;
        &#125;
    &#125;

private:

    CPU * m_cpu; //CPU的零件指针
    VideoCard * m_vc; //显卡零件指针
    Memory * m_mem; //内存条零件指针
&#125;;

//具体厂商
//Intel厂商
class IntelCPU :public CPU
&#123;
public:
    virtual void calculate()
    &#123;
        cout << "Intel的CPU开始计算了！" << endl;
    &#125;
&#125;;

class IntelVideoCard :public VideoCard
&#123;
public:
    virtual void display()
    &#123;
        cout << "Intel的显卡开始显示了！" << endl;
    &#125;
&#125;;

class IntelMemory :public Memory
&#123;
public:
    virtual void storage()
    &#123;
        cout << "Intel的内存条开始存储了！" << endl;
    &#125;
&#125;;

//Lenovo厂商
class LenovoCPU :public CPU
&#123;
public:
    virtual void calculate()
    &#123;
        cout << "Lenovo的CPU开始计算了！" << endl;
    &#125;
&#125;;

class LenovoVideoCard :public VideoCard
&#123;
public:
    virtual void display()
    &#123;
        cout << "Lenovo的显卡开始显示了！" << endl;
    &#125;
&#125;;

class LenovoMemory :public Memory
&#123;
public:
    virtual void storage()
    &#123;
        cout << "Lenovo的内存条开始存储了！" << endl;
    &#125;
&#125;;


void test01()
&#123;
    //第一台电脑零件
    CPU * intelCpu = new IntelCPU;
    VideoCard * intelCard = new IntelVideoCard;
    Memory * intelMem = new IntelMemory;

    cout << "第一台电脑开始工作：" << endl;
    //创建第一台电脑
    Computer * computer1 = new Computer(intelCpu, intelCard, intelMem);
    computer1->work();
    delete computer1;

    cout << "-----------------------" << endl;
    cout << "第二台电脑开始工作：" << endl;
    //第二台电脑组装
    Computer * computer2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);;
    computer2->work();
    delete computer2;

    cout << "-----------------------" << endl;
    cout << "第三台电脑开始工作：" << endl;
    //第三台电脑组装
    Computer * computer3 = new Computer(new LenovoCPU, new IntelVideoCard, new LenovoMemory);;
    computer3->work();
    delete computer3;

&#125;
</code></pre>
<h2 id="5-文件操作"><a href="#5-文件操作" class="headerlink" title="5 文件操作"></a>5 文件操作</h2><p>程序运行时产生的数据都属于临时数据，程序一旦运行结束都会被释放</p>
<p>通过<strong>文件可以将数据持久化</strong></p>
<p>C++中对文件操作需要包含头文件 ==&lt; fstream &gt;==</p>
<p>文件类型分为两种：</p>
<ol>
<li><strong>文本文件</strong>     -  文件以文本的<strong>ASCII码</strong>形式存储在计算机中</li>
<li><strong>二进制文件</strong> -  文件以文本的<strong>二进制</strong>形式存储在计算机中，用户一般不能直接读懂它们</li>
</ol>
<p>操作文件的三大类:</p>
<ol>
<li>ofstream：写操作</li>
<li>ifstream： 读操作</li>
<li>fstream ： 读写操作</li>
</ol>
<h3 id="5-1文本文件"><a href="#5-1文本文件" class="headerlink" title="5.1文本文件"></a>5.1文本文件</h3><h4 id="5-1-1写文件"><a href="#5-1-1写文件" class="headerlink" title="5.1.1写文件"></a>5.1.1写文件</h4><p>   写文件步骤如下：</p>
<ol>
<li><p>包含头文件   </p>
<p>  #include &lt;fstream&gt;</p>
</li>
<li><p>创建流对象  </p>
<p>ofstream ofs;</p>
</li>
<li><p>打开文件</p>
<p>ofs.open(“文件路径”,打开方式);</p>
</li>
<li><p>写数据</p>
<p>ofs &lt;&lt; “写入的数据”;</p>
</li>
<li><p>关闭文件</p>
<p>ofs.close();</p>
</li>
</ol>
<p>文件打开方式：</p>
<table>
<thead>
<tr>
<th>打开方式</th>
<th>解释</th>
</tr>
</thead>
<tbody><tr>
<td>ios::in</td>
<td>为读文件而打开文件</td>
</tr>
<tr>
<td>ios::out</td>
<td>为写文件而打开文件</td>
</tr>
<tr>
<td>ios::ate</td>
<td>初始位置：文件尾</td>
</tr>
<tr>
<td>ios::app</td>
<td>追加方式写文件</td>
</tr>
<tr>
<td>ios::trunc</td>
<td>如果文件存在先删除，再创建</td>
</tr>
<tr>
<td>ios::binary</td>
<td>二进制方式</td>
</tr>
</tbody></table>
<p><strong>注意：</strong> 文件打开方式可以配合使用，利用|操作符</p>
<p><strong>例如：</strong>用二进制方式写文件 <code>ios::binary |  ios:: out</code></p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">#include <fstream>

void test01()
&#123;
    ofstream ofs;
    ofs.open("test.txt", ios::out);

    ofs << "姓名：张三" << endl;
    ofs << "性别：男" << endl;
    ofs << "年龄：18" << endl;

    ofs.close();
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p>总结：</p>
<ul>
<li>文件操作必须包含头文件 fstream</li>
<li>读文件可以利用 ofstream  ，或者fstream类</li>
<li>打开文件时候需要指定操作文件的路径，以及打开方式</li>
<li>利用&lt;&lt;可以向文件中写数据</li>
<li>操作完毕，要关闭文件</li>
</ul>
<h4 id="5-1-2读文件"><a href="#5-1-2读文件" class="headerlink" title="5.1.2读文件"></a>5.1.2读文件</h4><p>读文件与写文件步骤相似，但是读取方式相对于比较多</p>
<p>读文件步骤如下：</p>
<ol>
<li><p>包含头文件   </p>
<p>  #include &lt;fstream&gt;</p>
</li>
<li><p>创建流对象  </p>
<p>ifstream ifs;</p>
</li>
<li><p>打开文件并判断文件是否打开成功</p>
<p>ifs.open(“文件路径”,打开方式);</p>
</li>
<li><p>读数据</p>
<p>四种方式读取</p>
</li>
<li><p>关闭文件</p>
<p>ifs.close();</p>
</li>
</ol>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">#include <fstream>
#include <string>
void test01()
&#123;
    ifstream ifs;
    ifs.open("test.txt", ios::in);

    if (!ifs.is_open())
    &#123;
        cout << "文件打开失败" << endl;
        return;
    &#125;

    //第一种方式
    //char buf[1024] = &#123; 0 &#125;;
    //while (ifs >> buf)
    //&#123;
    //    cout << buf << endl;
    //&#125;

    //第二种
    //char buf[1024] = &#123; 0 &#125;;
    //while (ifs.getline(buf,sizeof(buf)))
    //&#123;
    //    cout << buf << endl;
    //&#125;

    //第三种
    //string buf;
    //while (getline(ifs, buf))
    //&#123;
    //    cout << buf << endl;
    //&#125;

    char c;
    while ((c = ifs.get()) != EOF)
    &#123;
        cout << c;
    &#125;

    ifs.close();


&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p>总结：</p>
<ul>
<li>读文件可以利用 ifstream  ，或者fstream类</li>
<li>利用is_open函数可以判断文件是否打开成功</li>
<li>close 关闭文件 </li>
</ul>
<h3 id="5-2-二进制文件"><a href="#5-2-二进制文件" class="headerlink" title="5.2 二进制文件"></a>5.2 二进制文件</h3><p>以二进制的方式对文件进行读写操作</p>
<p>打开方式要指定为 ==ios::binary==</p>
<h4 id="5-2-1-写文件"><a href="#5-2-1-写文件" class="headerlink" title="5.2.1 写文件"></a>5.2.1 写文件</h4><p>二进制方式写文件主要利用流对象调用成员函数write</p>
<p>函数原型 ：<code>ostream&amp; write(const char * buffer,int len);</code></p>
<p>参数解释：字符指针buffer指向内存中一段存储空间。len是读写的字节数</p>
<p><strong>示例：</strong></p>
<pre class=" language-C++"><code class="language-C++">#include <fstream>
#include <string>

class Person
&#123;
public:
    char m_Name[64];
    int m_Age;
&#125;;

//二进制文件  写文件
void test01()
&#123;
    //1、包含头文件

    //2、创建输出流对象
    ofstream ofs("person.txt", ios::out | ios::binary);
    
    //3、打开文件
    //ofs.open("person.txt", ios::out | ios::binary);

    Person p = &#123;"张三"  , 18&#125;;

    //4、写文件
    ofs.write((const char *)&p, sizeof(p));

    //5、关闭文件
    ofs.close();
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<p>总结：</p>
<ul>
<li>文件输出流对象 可以通过write函数，以二进制方式写数据</li>
</ul>
<h4 id="5-2-2-读文件"><a href="#5-2-2-读文件" class="headerlink" title="5.2.2 读文件"></a>5.2.2 读文件</h4><p>二进制方式读文件主要利用流对象调用成员函数read</p>
<p>函数原型：<code>istream&amp; read(char *buffer,int len);</code></p>
<p>参数解释：字符指针buffer指向内存中一段存储空间。len是读写的字节数</p>
<p>示例：</p>
<pre class=" language-C++"><code class="language-C++">#include <fstream>
#include <string>

class Person
&#123;
public:
    char m_Name[64];
    int m_Age;
&#125;;

void test01()
&#123;
    ifstream ifs("person.txt", ios::in | ios::binary);
    if (!ifs.is_open())
    &#123;
        cout << "文件打开失败" << endl;
    &#125;

    Person p;
    ifs.read((char *)&p, sizeof(p));

    cout << "姓名： " << p.m_Name << " 年龄： " << p.m_Age << endl;
&#125;

int main() &#123;

    test01();

    system("pause");

    return 0;
&#125;
</code></pre>
<ul>
<li>文件输入流对象 可以通过read函数，以二进制方式读数据</li>
</ul>

                
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/dai_modest/about" rel="external nofollow noreferrer">戴某人</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://modest2001.gitee.io/dai_modest/dai_modest/2021/09/07/c-ji-chu-zong-jie/">https://modest2001.gitee.io/dai_modest/dai_modest/2021/09/07/c-ji-chu-zong-jie/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/dai_modest/about" target="_blank">戴某人</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/dai_modest/tags/c/">
                                    <span class="chip bg-color">c++</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/dai_modest/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/dai_modest/libs/share/js/social-share.min.js"></script>
    

    
    <script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid="></script>
    <div class="addthis_inline_share_toolbox"></div>
    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/dai_modest/medias/reward/alipay.jpg" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/dai_modest/medias/reward/wechat.png" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/dai_modest/2021/09/07/java-spring-jian-dan-zong-jie/">
                    <div class="card-image">
                        
                        
                        <img src="/dai_modest/medias/featureimages/8.jpg" class="responsive-img" alt="java,spring简单详讲">
                        
                        <span class="card-title">java,spring简单详讲</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2021-09-07
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/dai_modest/categories/ssm%E7%B1%BB/" class="post-category">
                                    ssm类
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/dai_modest/tags/java/">
                        <span class="chip bg-color">java</span>
                    </a>
                    
                    <a href="/dai_modest/tags/ssm/">
                        <span class="chip bg-color">ssm</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/dai_modest/2021/09/07/springmvc-chu-xue/">
                    <div class="card-image">
                        
                        
                        <img src="/dai_modest/medias/featureimages/13.jpg" class="responsive-img" alt="Springmvc 初学01">
                        
                        <span class="card-title">Springmvc 初学01</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2021-09-07
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/dai_modest/categories/ssm%E7%B1%BB/" class="post-category">
                                    ssm类
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/dai_modest/tags/java/">
                        <span class="chip bg-color">java</span>
                    </a>
                    
                    <a href="/dai_modest/tags/ssm/">
                        <span class="chip bg-color">ssm</span>
                    </a>
                    
                    <a href="/dai_modest/tags/mvc/">
                        <span class="chip bg-color">mvc</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>


<script>
    $('#articleContent').on('copy', function (e) {
        // IE8 or earlier browser is 'undefined'
        if (typeof window.getSelection === 'undefined') return;

        var selection = window.getSelection();
        // if the selection is short let's not annoy our users.
        if (('' + selection).length < Number.parseInt('120')) {
            return;
        }

        // create a div outside of the visible area and fill it with the selected text.
        var bodyElement = document.getElementsByTagName('body')[0];
        var newdiv = document.createElement('div');
        newdiv.style.position = 'absolute';
        newdiv.style.left = '-99999px';
        bodyElement.appendChild(newdiv);
        newdiv.appendChild(selection.getRangeAt(0).cloneContents());

        // we need a <pre> tag workaround.
        // otherwise the text inside "pre" loses all the line breaks!
        if (selection.getRangeAt(0).commonAncestorContainer.nodeName === 'PRE' || selection.getRangeAt(0).commonAncestorContainer.nodeName === 'CODE') {
            newdiv.innerHTML = "<pre>" + newdiv.innerHTML + "</pre>";
        }

        var url = document.location.href;
        newdiv.innerHTML += '<br />'
            + '来源: 戴某的博客<br />'
            + '文章作者: 戴某人<br />'
            + '文章链接: <a href="' + url + '">' + url + '</a><br />'
            + '本文章著作权归作者：戴某人所有，任何形式的转载都请注明出处。';

        selection.selectAllChildren(newdiv);
        window.setTimeout(function () {bodyElement.removeChild(newdiv);}, 200);
    });
</script>


<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/dai_modest/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/dai_modest/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/dai_modest/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/dai_modest/libs/codeBlock/codeShrink.js"></script>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/dai_modest/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/dai_modest/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="503838841"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/dai_modest/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    

    <div class="container row center-align"
         style="margin-bottom: 0px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2019-2023</span>
            
            <span id="year">2019</span>
            <a href="/dai_modest/about" target="_blank">戴某人</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
                &nbsp;<i class="fas fa-chart-area"></i>&nbsp;站点总字数:&nbsp;<span
                        class="white-color">128.1k</span>
            
            
            
                
            
            
                <span id="busuanzi_container_site_pv">
                &nbsp;|&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;
                    <span id="busuanzi_value_site_pv" class="white-color"></span>
            </span>
            
            
                <span id="busuanzi_container_site_uv">
                &nbsp;|&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;
                    <span id="busuanzi_value_site_uv" class="white-color"></span>
            </span>
            
            <br>

            <!-- 运行天数提醒. -->
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">


    <a href="mailto:861796830@qq.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=861796830" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 861796830" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







    <a href="/dai_modest/atom.xml" class="tooltipped" target="_blank" data-tooltip="RSS 订阅" data-position="top" data-delay="50">
        <i class="fas fa-rss"></i>
    </a>

</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/dai_modest/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/dai_modest/libs/materialize/materialize.min.js"></script>
    <script src="/dai_modest/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/dai_modest/libs/aos/aos.js"></script>
    <script src="/dai_modest/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/dai_modest/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/dai_modest/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/dai_modest/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/dai_modest/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
        <div style="position:fixed;bottom:125px;right:16px;cursor: pointer;">
            <a title="兔小巢" target="_blank" rel="noopener" href="https://support.qq.com/products/"><i class="fa fa-comments fa-3x"  aria-hidden="true"></i></a>
        </div>
    
    
    <script type="text/javascript" color="0,0,255"
        pointColor="0,0,255" opacity='0.7'
        zIndex="-1" count="99"
        src="/dai_modest/libs/background/canvas-nest.js"></script>
    

    
    
    <script type="text/javascript" size="150" alpha='0.6'
        zIndex="-1" src="/dai_modest/libs/background/ribbon.min.js" async="async"></script>
    

    
    <script type="text/javascript" src="/dai_modest/libs/background/ribbon-dynamic.js" async="async"></script>
    

    
    <script src="/dai_modest/libs/instantpage/instantpage.js" type="module"></script>
    

<script src="/dai_modest/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>

</html>
